model.py 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266
  1. """!
  2. @package gmodeler.model
  3. @brief wxGUI Graphical Modeler (base classes & read/write)
  4. Classes:
  5. - model::Model
  6. - model::ModelObject
  7. - model::ModelAction
  8. - model::ModelData
  9. - model::ModelRelation
  10. - model::ModelItem
  11. - model::ModelLoop
  12. - model::ModelCondition
  13. - model::ProcessModelFile
  14. - model::WriteModelFile
  15. - model::WritePythonFile
  16. - model::ModelParamDialog
  17. (C) 2010-2012 by the GRASS Development Team
  18. This program is free software under the GNU General Public License
  19. (>=v2). Read the file COPYING that comes with GRASS for details.
  20. @author Martin Landa <landa.martin gmail.com>
  21. """
  22. import os
  23. import getpass
  24. import copy
  25. import re
  26. import mimetypes
  27. import time
  28. try:
  29. import xml.etree.ElementTree as etree
  30. except ImportError:
  31. import elementtree.ElementTree as etree # Python <= 2.4
  32. import wx
  33. from wx.lib import ogl
  34. from core import globalvar
  35. from core import utils
  36. from core.gcmd import GMessage, GException, GError, RunCommand, EncodeString, GWarning, GetDefaultEncoding
  37. from core.settings import UserSettings
  38. from gui_core.forms import GUI, CmdPanel
  39. from gui_core.widgets import GNotebook
  40. from grass.script import core as grass
  41. from grass.script import task as gtask
  42. class Model(object):
  43. """!Class representing the model"""
  44. def __init__(self, canvas = None):
  45. self.items = list() # list of actions/loops/...
  46. # model properties
  47. self.properties = { 'name' : _("model"),
  48. 'description' : _("Script generated by wxGUI Graphical Modeler."),
  49. 'author' : getpass.getuser() }
  50. # model variables
  51. self.variables = dict()
  52. self.variablesParams = dict()
  53. self.canvas = canvas
  54. def GetCanvas(self):
  55. """!Get canvas or None"""
  56. return self.canvas
  57. def GetItems(self, objType = None):
  58. """!Get list of model items
  59. @param objType Object type to filter model objects
  60. """
  61. if not objType:
  62. return self.items
  63. result = list()
  64. for item in self.items:
  65. if isinstance(item, objType):
  66. result.append(item)
  67. return result
  68. def GetItem(self, aId):
  69. """!Get item of given id
  70. @param aId item id
  71. @return Model* instance
  72. @return None if no item found
  73. """
  74. ilist = self.GetItems()
  75. for item in ilist:
  76. if item.GetId() == aId:
  77. return item
  78. return None
  79. def GetNumItems(self, actionOnly = False):
  80. """!Get number of items"""
  81. if actionOnly:
  82. return len(self.GetItems(objType = ModelAction))
  83. return len(self.GetItems())
  84. def GetNextId(self):
  85. """!Get next id (data ignored)
  86. @return next id to be used (default: 1)
  87. """
  88. if len(self.items) < 1:
  89. return 1
  90. currId = self.items[-1].GetId()
  91. if currId > 0:
  92. return currId + 1
  93. return 1
  94. def GetProperties(self):
  95. """!Get model properties"""
  96. return self.properties
  97. def GetVariables(self, params = False):
  98. """!Get model variables"""
  99. if params:
  100. return self.variablesParams
  101. return self.variables
  102. def SetVariables(self, data):
  103. """!Set model variables"""
  104. self.variables = data
  105. def Reset(self):
  106. """!Reset model"""
  107. self.items = list()
  108. def RemoveItem(self, item):
  109. """!Remove item from model
  110. @return list of related items to remove/update
  111. """
  112. relList = list()
  113. upList = list()
  114. if not isinstance(item, ModelData):
  115. self.items.remove(item)
  116. if isinstance(item, ModelAction):
  117. for rel in item.GetRelations():
  118. relList.append(rel)
  119. data = rel.GetData()
  120. if len(data.GetRelations()) < 2:
  121. relList.append(data)
  122. else:
  123. upList.append(data)
  124. elif isinstance(item, ModelData):
  125. for rel in item.GetRelations():
  126. relList.append(rel)
  127. if rel.GetFrom() == self:
  128. relList.append(rel.GetTo())
  129. else:
  130. relList.append(rel.GetFrom())
  131. elif isinstance(item, ModelLoop):
  132. for rel in item.GetRelations():
  133. relList.append(rel)
  134. for action in self.GetItems():
  135. action.UnSetBlock(item)
  136. return relList, upList
  137. def FindAction(self, aId):
  138. """!Find action by id"""
  139. alist = self.GetItems(objType = ModelAction)
  140. for action in alist:
  141. if action.GetId() == aId:
  142. return action
  143. return None
  144. def GetMaps(self, prompt):
  145. """!Get list of maps of selected type
  146. @param promt to filter maps"""
  147. maps = list()
  148. for data in self.GetData():
  149. if prompt == data.GetPrompt():
  150. maps.append(data.GetValue())
  151. return maps
  152. def GetData(self):
  153. """!Get list of data items"""
  154. result = list()
  155. dataItems = self.GetItems(objType = ModelData)
  156. for action in self.GetItems(objType = ModelAction):
  157. for rel in action.GetRelations():
  158. dataItem = rel.GetData()
  159. if dataItem not in result:
  160. result.append(dataItem)
  161. if dataItem in dataItems:
  162. dataItems.remove(dataItem)
  163. # standalone data
  164. if dataItems:
  165. result += dataItems
  166. return result
  167. def FindData(self, value, prompt):
  168. """!Find data item in the model
  169. @param value value
  170. @param prompt prompt
  171. @return ModelData instance
  172. @return None if not found
  173. """
  174. for data in self.GetData():
  175. if data.GetValue() == value and \
  176. data.GetPrompt() == prompt:
  177. return data
  178. return None
  179. def LoadModel(self, filename):
  180. """!Load model definition stored in GRASS Model XML file (gxm)
  181. @todo Validate against DTD
  182. Raise exception on error.
  183. """
  184. dtdFilename = os.path.join(globalvar.ETCWXDIR, "xml", "grass-gxm.dtd")
  185. # parse workspace file
  186. try:
  187. gxmXml = ProcessModelFile(etree.parse(filename))
  188. except StandardError, e:
  189. raise GException(e)
  190. if self.canvas:
  191. win = self.canvas.parent
  192. if gxmXml.pos:
  193. win.SetPosition(gxmXml.pos)
  194. if gxmXml.size:
  195. win.SetSize(gxmXml.size)
  196. # load properties
  197. self.properties = gxmXml.properties
  198. self.variables = gxmXml.variables
  199. # load model.GetActions()
  200. for action in gxmXml.actions:
  201. actionItem = ModelAction(parent = self,
  202. x = action['pos'][0],
  203. y = action['pos'][1],
  204. width = action['size'][0],
  205. height = action['size'][1],
  206. task = action['task'],
  207. id = action['id'])
  208. if action['disabled']:
  209. actionItem.Enable(False)
  210. self.AddItem(actionItem)
  211. actionItem.SetValid(actionItem.GetTask().get_options())
  212. actionItem.GetLog() # substitute variables (-> valid/invalid)
  213. # load data & relations
  214. for data in gxmXml.data:
  215. dataItem = ModelData(parent = self,
  216. x = data['pos'][0],
  217. y = data['pos'][1],
  218. width = data['size'][0],
  219. height = data['size'][1],
  220. prompt = data['prompt'],
  221. value = data['value'])
  222. dataItem.SetIntermediate(data['intermediate'])
  223. for rel in data['rels']:
  224. actionItem = self.FindAction(rel['id'])
  225. if rel['dir'] == 'from':
  226. relation = ModelRelation(parent = self, fromShape = dataItem,
  227. toShape = actionItem, param = rel['name'])
  228. else:
  229. relation = ModelRelation(parent = self, fromShape = actionItem,
  230. toShape = dataItem, param = rel['name'])
  231. relation.SetControlPoints(rel['points'])
  232. actionItem.AddRelation(relation)
  233. dataItem.AddRelation(relation)
  234. if self.canvas:
  235. dataItem.Update()
  236. # load loops
  237. for loop in gxmXml.loops:
  238. loopItem = ModelLoop(parent = self,
  239. x = loop['pos'][0],
  240. y = loop['pos'][1],
  241. width = loop['size'][0],
  242. height = loop['size'][1],
  243. text = loop['text'],
  244. id = loop['id'])
  245. self.AddItem(loopItem)
  246. # load conditions
  247. for condition in gxmXml.conditions:
  248. conditionItem = ModelCondition(parent = self,
  249. x = condition['pos'][0],
  250. y = condition['pos'][1],
  251. width = condition['size'][0],
  252. height = condition['size'][1],
  253. text = condition['text'],
  254. id = condition['id'])
  255. self.AddItem(conditionItem)
  256. # define loops & if/else items
  257. for loop in gxmXml.loops:
  258. alist = list()
  259. for aId in loop['items']:
  260. action = self.GetItem(aId)
  261. alist.append(action)
  262. loopItem = self.GetItem(loop['id'])
  263. loopItem.SetItems(alist)
  264. for action in loopItem.GetItems():
  265. action.SetBlock(loopItem)
  266. for condition in gxmXml.conditions:
  267. conditionItem = self.GetItem(condition['id'])
  268. for b in condition['items'].keys():
  269. alist = list()
  270. for aId in condition['items'][b]:
  271. action = self.GetItem(aId)
  272. alist.append(action)
  273. conditionItem.SetItems(alist, branch = b)
  274. items = conditionItem.GetItems()
  275. for b in items.keys():
  276. for action in items[b]:
  277. action.SetBlock(conditionItem)
  278. def AddItem(self, newItem):
  279. """!Add item to the list"""
  280. iId = newItem.GetId()
  281. i = 0
  282. for item in self.items:
  283. if item.GetId() > iId:
  284. self.items.insert(i, newItem)
  285. return
  286. i += 1
  287. self.items.append(newItem)
  288. def IsValid(self):
  289. """Return True if model is valid"""
  290. if self.Validate():
  291. return False
  292. return True
  293. def Validate(self):
  294. """!Validate model, return None if model is valid otherwise
  295. error string"""
  296. errList = list()
  297. variables = self.GetVariables().keys()
  298. pattern = re.compile(r'(.*)(%.+\s?)(.*)')
  299. for action in self.GetItems(objType = ModelAction):
  300. cmd = action.GetLog(string = False)
  301. task = GUI(show = None).ParseCommand(cmd = cmd)
  302. errList += map(lambda x: cmd[0] + ': ' + x, task.get_cmd_error())
  303. # check also variables
  304. for opt in cmd[1:]:
  305. if '=' not in opt:
  306. continue
  307. key, value = opt.split('=', 1)
  308. sval = pattern.search(value)
  309. if sval:
  310. var = sval.group(2).strip()[1:] # ignore '%'
  311. if var not in variables:
  312. report = True
  313. for item in filter(lambda x: isinstance(x, ModelLoop), action.GetBlock()):
  314. if var in item.GetText():
  315. report = False
  316. break
  317. if report:
  318. errList.append(cmd[0] + ": " + _("undefined variable '%s'") % var)
  319. ### TODO: check variables in file only optionally
  320. ### errList += self._substituteFile(action, checkOnly = True)
  321. return errList
  322. def _substituteFile(self, item, params = None, checkOnly = False):
  323. """!Subsitute variables in command file inputs
  324. @param checkOnly tuble - True to check variable, don't touch files
  325. @return list of undefined variables
  326. """
  327. errList = list()
  328. self.fileInput = dict()
  329. # collect ascii inputs
  330. for p in item.GetParams()['params']:
  331. if p.get('element', '') == 'file' and \
  332. p.get('prompt', '') == 'input' and \
  333. p.get('age', '') == 'old':
  334. filename = p.get('value', p.get('default', ''))
  335. if filename and \
  336. mimetypes.guess_type(filename)[0] == 'text/plain':
  337. self.fileInput[filename] = None
  338. for finput in self.fileInput:
  339. # read lines
  340. fd = open(finput, "r")
  341. try:
  342. data = self.fileInput[finput] = fd.read()
  343. finally:
  344. fd.close()
  345. # substitute variables
  346. write = False
  347. variables = self.GetVariables()
  348. for variable in variables:
  349. pattern = re.compile('%' + variable)
  350. value = ''
  351. if params and 'variables' in params:
  352. for p in params['variables']['params']:
  353. if variable == p.get('name', ''):
  354. if p.get('type', 'string') == 'string':
  355. value = p.get('value', '')
  356. else:
  357. value = str(p.get('value', ''))
  358. break
  359. if not value:
  360. value = variables[variable].get('value', '')
  361. data = pattern.sub(value, data)
  362. if not checkOnly:
  363. write = True
  364. pattern = re.compile(r'(.*)(%.+\s?)(.*)')
  365. sval = pattern.search(data)
  366. if sval:
  367. var = sval.group(2).strip()[1:] # ignore '%'
  368. cmd = item.GetLog(string = False)[0]
  369. errList.append(cmd + ": " + _("undefined variable '%s'") % var)
  370. if not checkOnly:
  371. if write:
  372. fd = open(finput, "w")
  373. try:
  374. fd.write(data)
  375. finally:
  376. fd.close()
  377. else:
  378. self.fileInput[finput] = None
  379. return errList
  380. def OnPrepare(self, item, params):
  381. self._substituteFile(item, params, checkOnly = False)
  382. def RunAction(self, item, params, log, onDone, onPrepare = None, statusbar = None):
  383. """!Run given action
  384. @param item action item
  385. @param params parameters dict
  386. @param log logging window
  387. @param onDone on-done method
  388. @param onPrepare on-prepare method
  389. @param statusbar wx.StatusBar instance or None
  390. """
  391. name = item.GetName()
  392. if name in params:
  393. paramsOrig = item.GetParams(dcopy = True)
  394. item.MergeParams(params[name])
  395. if statusbar:
  396. statusbar.SetStatusText(_('Running model...'), 0)
  397. data = { 'item' : item,
  398. 'params' : copy.deepcopy(params) }
  399. log.RunCmd(command = item.GetLog(string = False, substitute = params),
  400. onDone = onDone, onPrepare = self.OnPrepare, userData = data)
  401. if name in params:
  402. item.SetParams(paramsOrig)
  403. def Run(self, log, onDone, parent = None):
  404. """!Run model
  405. @param log logging window (see gconsole.GConsole)
  406. @param onDone on-done method
  407. @param parent window for messages or None
  408. """
  409. if self.GetNumItems() < 1:
  410. GMessage(parent = parent,
  411. message = _('Model is empty. Nothing to run.'))
  412. return
  413. statusbar = None
  414. if isinstance(parent, wx.Frame):
  415. statusbar = parent.GetStatusBar()
  416. # validation
  417. if statusbar:
  418. statusbar.SetStatusText(_('Validating model...'), 0)
  419. errList = self.Validate()
  420. if statusbar:
  421. statusbar.SetStatusText('', 0)
  422. if errList:
  423. dlg = wx.MessageDialog(parent = parent,
  424. message = _('Model is not valid. Do you want to '
  425. 'run the model anyway?\n\n%s') % '\n'.join(errList),
  426. caption = _("Run model?"),
  427. style = wx.YES_NO | wx.NO_DEFAULT |
  428. wx.ICON_QUESTION | wx.CENTRE)
  429. ret = dlg.ShowModal()
  430. dlg.Destroy()
  431. if ret != wx.ID_YES:
  432. return
  433. # parametrization
  434. params = self.Parameterize()
  435. delInterData = False
  436. if params:
  437. dlg = ModelParamDialog(parent = parent,
  438. params = params)
  439. dlg.CenterOnParent()
  440. ret = dlg.ShowModal()
  441. if ret != wx.ID_OK:
  442. dlg.Destroy()
  443. return
  444. err = dlg.GetErrors()
  445. delInterData = dlg.DeleteIntermediateData()
  446. dlg.Destroy()
  447. if err:
  448. GError(parent = parent, message = unicode('\n'.join(err)))
  449. return
  450. err = list()
  451. for key, item in params.iteritems():
  452. for p in item['params']:
  453. if p.get('value', '') == '':
  454. err.append((key, p.get('name', ''), p.get('description', '')))
  455. if err:
  456. GError(parent = parent,
  457. message = _("Variables below not defined:") + \
  458. "\n\n" + unicode('\n'.join(map(lambda x: "%s: %s (%s)" % (x[0], x[1], x[2]), err))))
  459. return
  460. log.cmdThread.SetId(-1)
  461. for item in self.GetItems():
  462. if not item.IsEnabled():
  463. continue
  464. if isinstance(item, ModelAction):
  465. if item.GetBlockId():
  466. continue
  467. self.RunAction(item, params, log, onDone)
  468. elif isinstance(item, ModelLoop):
  469. cond = item.GetText()
  470. # substitute variables in condition
  471. variables = self.GetVariables()
  472. for variable in variables:
  473. pattern = re.compile('%' + variable)
  474. if pattern.search(cond):
  475. value = ''
  476. if params and 'variables' in params:
  477. for p in params['variables']['params']:
  478. if variable == p.get('name', ''):
  479. value = p.get('value', '')
  480. break
  481. if not value:
  482. value = variables[variable].get('value', '')
  483. if not value:
  484. continue
  485. vtype = variables[variable].get('type', 'string')
  486. if vtype == 'string':
  487. value = '"' + value + '"'
  488. cond = pattern.sub(value, cond)
  489. # split condition
  490. condVar, condText = map(lambda x: x.strip(), re.split('\s*in\s*', cond))
  491. pattern = re.compile('%' + condVar)
  492. ### for vars()[condVar] in eval(condText): ?
  493. vlist = list()
  494. if condText[0] == '`' and condText[-1] == '`':
  495. # run command
  496. cmd, dcmd = utils.CmdToTuple(condText[1:-1].split(' '))
  497. ret = RunCommand(cmd,
  498. read = True,
  499. **dcmd)
  500. if ret:
  501. vlist = ret.splitlines()
  502. else:
  503. vlist = eval(condText)
  504. if 'variables' not in params:
  505. params['variables'] = { 'params' : [] }
  506. varDict = { 'name' : condVar, 'value' : '' }
  507. params['variables']['params'].append(varDict)
  508. for var in vlist:
  509. for action in item.GetItems():
  510. if not isinstance(action, ModelAction) or \
  511. not action.IsEnabled():
  512. continue
  513. varDict['value'] = var
  514. self.RunAction(item = action, params = params,
  515. log = log, onDone = onDone)
  516. params['variables']['params'].remove(varDict)
  517. if delInterData:
  518. self.DeleteIntermediateData(log)
  519. # discard values
  520. if params:
  521. for item in params.itervalues():
  522. for p in item['params']:
  523. p['value'] = ''
  524. def DeleteIntermediateData(self, log):
  525. """!Detele intermediate data"""
  526. rast, vect, rast3d, msg = self.GetIntermediateData()
  527. if rast:
  528. log.RunCmd(['g.remove', 'rast=%s' %','.join(rast)])
  529. if rast3d:
  530. log.RunCmd(['g.remove', 'rast3d=%s' %','.join(rast3d)])
  531. if vect:
  532. log.RunCmd(['g.remove', 'vect=%s' %','.join(vect)])
  533. def GetIntermediateData(self):
  534. """!Get info about intermediate data"""
  535. rast = list()
  536. rast3d = list()
  537. vect = list()
  538. for data in self.GetData():
  539. if not data.IsIntermediate():
  540. continue
  541. name = data.GetValue()
  542. prompt = data.GetPrompt()
  543. if prompt == 'raster':
  544. rast.append(name)
  545. elif prompt == 'vector':
  546. vect.append(name)
  547. elif prompt == 'rast3d':
  548. rast3d.append(name)
  549. msg = ''
  550. if rast:
  551. msg += '\n\n%s: ' % _('Raster maps')
  552. msg += ', '.join(rast)
  553. if rast3d:
  554. msg += '\n\n%s: ' % _('3D raster maps')
  555. msg += ', '.join(rast3d)
  556. if vect:
  557. msg += '\n\n%s: ' % _('Vector maps')
  558. msg += ', '.join(vect)
  559. return rast, vect, rast3d, msg
  560. def Update(self):
  561. """!Update model"""
  562. for item in self.items:
  563. item.Update()
  564. def IsParameterized(self):
  565. """!Return True if model is parameterized"""
  566. if self.Parameterize():
  567. return True
  568. return False
  569. def Parameterize(self):
  570. """!Return parameterized options"""
  571. result = dict()
  572. idx = 0
  573. if self.variables:
  574. params = list()
  575. result["variables"] = { 'flags' : list(),
  576. 'params' : params,
  577. 'idx' : idx }
  578. for name, values in self.variables.iteritems():
  579. gtype = values.get('type', 'string')
  580. if gtype in ('raster', 'vector', 'mapset', 'file'):
  581. gisprompt = True
  582. prompt = gtype
  583. if gtype == 'raster':
  584. element = 'cell'
  585. else:
  586. element = gtype
  587. ptype = 'string'
  588. else:
  589. gisprompt = False
  590. prompt = None
  591. element = None
  592. ptype = gtype
  593. params.append({ 'gisprompt' : gisprompt,
  594. 'multiple' : False,
  595. 'description' : values.get('description', ''),
  596. 'guidependency' : '',
  597. 'default' : '',
  598. 'age' : None,
  599. 'required' : True,
  600. 'value' : values.get('value', ''),
  601. 'label' : '',
  602. 'guisection' : '',
  603. 'key_desc' : '',
  604. 'values' : list(),
  605. 'parameterized' : False,
  606. 'values_desc' : list(),
  607. 'prompt' : prompt,
  608. 'element' : element,
  609. 'type' : ptype,
  610. 'name' : name })
  611. idx += 1
  612. for action in self.GetItems(objType = ModelAction):
  613. if not action.IsEnabled():
  614. continue
  615. name = action.GetName()
  616. params = action.GetParams()
  617. for f in params['flags']:
  618. if f.get('parameterized', False):
  619. if name not in result:
  620. result[name] = { 'flags' : list(),
  621. 'params': list(),
  622. 'idx' : idx }
  623. result[name]['flags'].append(f)
  624. for p in params['params']:
  625. if p.get('parameterized', False):
  626. if name not in result:
  627. result[name] = { 'flags' : list(),
  628. 'params': list(),
  629. 'idx' : idx }
  630. result[name]['params'].append(p)
  631. if name in result:
  632. idx += 1
  633. self.variablesParams = result # record parameters
  634. return result
  635. class ModelObject(object):
  636. def __init__(self, id = -1):
  637. self.id = id
  638. self.rels = list() # list of ModelRelations
  639. self.isEnabled = True
  640. self.inBlock = list() # list of related loops/conditions
  641. def __del__(self):
  642. pass
  643. def GetId(self):
  644. """!Get id"""
  645. return self.id
  646. def AddRelation(self, rel):
  647. """!Record new relation
  648. """
  649. self.rels.append(rel)
  650. def GetRelations(self, fdir = None):
  651. """!Get list of relations
  652. @param fdir True for 'from'
  653. """
  654. if fdir is None:
  655. return self.rels
  656. result = list()
  657. for rel in self.rels:
  658. if fdir == 'from':
  659. if rel.GetFrom() == self:
  660. result.append(rel)
  661. else:
  662. if rel.GetTo() == self:
  663. result.append(rel)
  664. return result
  665. def IsEnabled(self):
  666. """!Get True if action is enabled, otherwise False"""
  667. return self.isEnabled
  668. def Enable(self, enabled = True):
  669. """!Enable/disable action"""
  670. self.isEnabled = enabled
  671. self.Update()
  672. def Update(self):
  673. pass
  674. def SetBlock(self, item):
  675. """!Add object to the block (loop/condition)
  676. @param item reference to ModelLoop or ModelCondition which
  677. defines loops/condition
  678. """
  679. if item not in self.inBlock:
  680. self.inBlock.append(item)
  681. def UnSetBlock(self, item):
  682. """!Remove object from the block (loop/consition)
  683. @param item reference to ModelLoop or ModelCondition which
  684. defines loops/codition
  685. """
  686. if item in self.inBlock:
  687. self.inBlock.remove(item)
  688. def GetBlock(self):
  689. """!Get list of related ModelObject(s) which defines block
  690. (loop/condition)
  691. @return list of ModelObjects
  692. """
  693. return self.inBlock
  694. def GetBlockId(self):
  695. """!Get list of related ids which defines block
  696. @return list of ids
  697. """
  698. ret = list()
  699. for mo in self.inBlock:
  700. ret.append(mo.GetId())
  701. return ret
  702. class ModelAction(ModelObject, ogl.RectangleShape):
  703. """!Action class (GRASS module)"""
  704. def __init__(self, parent, x, y, id = -1, cmd = None, task = None, width = None, height = None):
  705. ModelObject.__init__(self, id)
  706. self.parent = parent
  707. self.task = task
  708. if not width:
  709. width = UserSettings.Get(group='modeler', key='action', subkey=('size', 'width'))
  710. if not height:
  711. height = UserSettings.Get(group='modeler', key='action', subkey=('size', 'height'))
  712. if cmd:
  713. self.task = GUI(show = None).ParseCommand(cmd = cmd)
  714. else:
  715. if task:
  716. self.task = task
  717. else:
  718. self.task = None
  719. self.propWin = None
  720. self.data = list() # list of connected data items
  721. self.isValid = False
  722. self.isParameterized = False
  723. if self.parent.GetCanvas():
  724. ogl.RectangleShape.__init__(self, width, height)
  725. self.SetCanvas(self.parent)
  726. self.SetX(x)
  727. self.SetY(y)
  728. self.SetPen(wx.BLACK_PEN)
  729. self._setPen()
  730. self._setBrush()
  731. self.SetId(id)
  732. if self.task:
  733. self.SetValid(self.task.get_options())
  734. def _setBrush(self, running = False):
  735. """!Set brush"""
  736. if running:
  737. color = UserSettings.Get(group='modeler', key='action',
  738. subkey=('color', 'running'))
  739. elif not self.isEnabled:
  740. color = UserSettings.Get(group='modeler', key='disabled',
  741. subkey='color')
  742. elif self.isValid:
  743. color = UserSettings.Get(group='modeler', key='action',
  744. subkey=('color', 'valid'))
  745. else:
  746. color = UserSettings.Get(group='modeler', key='action',
  747. subkey=('color', 'invalid'))
  748. wxColor = wx.Colour(color[0], color[1], color[2])
  749. self.SetBrush(wx.Brush(wxColor))
  750. def _setPen(self):
  751. """!Set pen"""
  752. if self.isParameterized:
  753. width = int(UserSettings.Get(group='modeler', key='action',
  754. subkey=('width', 'parameterized')))
  755. else:
  756. width = int(UserSettings.Get(group='modeler', key='action',
  757. subkey=('width', 'default')))
  758. pen = self.GetPen()
  759. pen.SetWidth(width)
  760. self.SetPen(pen)
  761. def SetId(self, id):
  762. """!Set id"""
  763. self.id = id
  764. cmd = self.task.get_cmd(ignoreErrors = True)
  765. if cmd and len(cmd) > 0:
  766. self.ClearText()
  767. self.AddText('(%d) %s' % (self.id, cmd[0]))
  768. else:
  769. self.AddText('(%d) <<%s>>' % (self.id, _("unknown")))
  770. def SetProperties(self, params, propwin):
  771. """!Record properties dialog"""
  772. self.task.params = params['params']
  773. self.task.flags = params['flags']
  774. self.propWin = propwin
  775. def GetPropDialog(self):
  776. """!Get properties dialog"""
  777. return self.propWin
  778. def GetLog(self, string = True, substitute = None):
  779. """!Get logging info
  780. @param string True to get cmd as a string otherwise a list
  781. @param substitute dictionary of parameter to substitute or None
  782. """
  783. cmd = self.task.get_cmd(ignoreErrors = True, ignoreRequired = True,
  784. ignoreDefault = False)
  785. # substitute variables
  786. if substitute:
  787. variables = []
  788. if 'variables' in substitute:
  789. for p in substitute['variables']['params']:
  790. variables.append(p.get('name', ''))
  791. else:
  792. variables = self.parent.GetVariables()
  793. for variable in variables:
  794. pattern= re.compile('%' + variable)
  795. value = ''
  796. if substitute and 'variables' in substitute:
  797. for p in substitute['variables']['params']:
  798. if variable == p.get('name', ''):
  799. if p.get('type', 'string') == 'string':
  800. value = p.get('value', '')
  801. else:
  802. value = str(p.get('value', ''))
  803. break
  804. if not value:
  805. value = variables[variable].get('value', '')
  806. if not value:
  807. continue
  808. for idx in range(len(cmd)):
  809. if pattern.search(cmd[idx]):
  810. cmd[idx] = pattern.sub(value, cmd[idx])
  811. break
  812. idx += 1
  813. if string:
  814. if cmd is None:
  815. return ''
  816. else:
  817. return ' '.join(cmd)
  818. return cmd
  819. def GetName(self):
  820. """!Get name"""
  821. cmd = self.task.get_cmd(ignoreErrors = True)
  822. if cmd and len(cmd) > 0:
  823. return cmd[0]
  824. return _('unknown')
  825. def GetParams(self, dcopy = False):
  826. """!Get dictionary of parameters"""
  827. if dcopy:
  828. return copy.deepcopy(self.task.get_options())
  829. return self.task.get_options()
  830. def GetTask(self):
  831. """!Get grassTask instance"""
  832. return self.task
  833. def SetParams(self, params):
  834. """!Set dictionary of parameters"""
  835. self.task.params = params['params']
  836. self.task.flags = params['flags']
  837. def MergeParams(self, params):
  838. """!Merge dictionary of parameters"""
  839. if 'flags' in params:
  840. for f in params['flags']:
  841. self.task.set_flag(f['name'],
  842. f.get('value', False))
  843. if 'params' in params:
  844. for p in params['params']:
  845. self.task.set_param(p['name'],
  846. p.get('value', ''))
  847. def SetValid(self, options):
  848. """!Set validity for action
  849. @param options dictionary with flags and params (gtask)
  850. """
  851. self.isValid = True
  852. self.isParameterized = False
  853. for f in options['flags']:
  854. if f.get('parameterized', False):
  855. self.IsParameterized = True
  856. break
  857. for p in options['params']:
  858. if self.isValid and p.get('required', False) and \
  859. p.get('value', '') == '' and \
  860. p.get('default', '') == '':
  861. self.isValid = False
  862. if not self.isParameterized and p.get('parameterized', False):
  863. self.isParameterized = True
  864. if self.parent.GetCanvas():
  865. self._setBrush()
  866. self._setPen()
  867. def IsValid(self):
  868. """!Check validity (all required parameters set)"""
  869. return self.isValid
  870. def IsParameterized(self):
  871. """!Check if action is parameterized"""
  872. return self.isParameterized
  873. def FindData(self, name):
  874. """!Find data item by name"""
  875. for rel in self.GetRelations():
  876. data = rel.GetData()
  877. if name == rel.GetName() and name in data.GetName():
  878. return data
  879. return None
  880. def Update(self, running = False):
  881. """!Update action"""
  882. if running:
  883. self._setBrush(running = True)
  884. else:
  885. self._setBrush()
  886. self._setPen()
  887. def OnDraw(self, dc):
  888. """!Draw action in canvas"""
  889. self._setBrush()
  890. self._setPen()
  891. ogl.RectangleShape.Recentre(self, dc) # re-center text
  892. ogl.RectangleShape.OnDraw(self, dc)
  893. class ModelData(ModelObject, ogl.EllipseShape):
  894. def __init__(self, parent, x, y, value = '', prompt = '', width = None, height = None):
  895. """Data item class
  896. @param parent window parent
  897. @param x, y position of the shape
  898. @param fname, tname list of parameter names from / to
  899. @param value value
  900. @param prompt type of GIS element
  901. @param width,height dimension of the shape
  902. """
  903. ModelObject.__init__(self)
  904. self.parent = parent
  905. self.value = value
  906. self.prompt = prompt
  907. self.intermediate = False
  908. self.propWin = None
  909. if not width:
  910. width = UserSettings.Get(group='modeler', key='data', subkey=('size', 'width'))
  911. if not height:
  912. height = UserSettings.Get(group='modeler', key='data', subkey=('size', 'height'))
  913. if self.parent.GetCanvas():
  914. ogl.EllipseShape.__init__(self, width, height)
  915. self.SetCanvas(self.parent)
  916. self.SetX(x)
  917. self.SetY(y)
  918. self.SetPen(wx.BLACK_PEN)
  919. self._setBrush()
  920. self._setText()
  921. def IsIntermediate(self):
  922. """!Checks if data item is intermediate"""
  923. return self.intermediate
  924. def SetIntermediate(self, im):
  925. """!Set intermediate flag"""
  926. self.intermediate = im
  927. def OnDraw(self, dc):
  928. pen = self.GetPen()
  929. pen.SetWidth(1)
  930. if self.intermediate:
  931. pen.SetStyle(wx.SHORT_DASH)
  932. else:
  933. pen.SetStyle(wx.SOLID)
  934. self.SetPen(pen)
  935. ogl.EllipseShape.OnDraw(self, dc)
  936. def GetLog(self, string = True):
  937. """!Get logging info"""
  938. name = list()
  939. for rel in self.GetRelations():
  940. name.append(rel.GetName())
  941. if name:
  942. return '/'.join(name) + '=' + self.value + ' (' + self.prompt + ')'
  943. else:
  944. return self.value + ' (' + self.prompt + ')'
  945. def GetName(self):
  946. """!Get list of names"""
  947. name = list()
  948. for rel in self.GetRelations():
  949. name.append(rel.GetName())
  950. return name
  951. def GetPrompt(self):
  952. """!Get prompt"""
  953. return self.prompt
  954. def SetPrompt(self, prompt):
  955. """!Set prompt
  956. @param prompt
  957. """
  958. self.prompt = prompt
  959. def GetValue(self):
  960. """!Get value"""
  961. return self.value
  962. def SetValue(self, value):
  963. """!Set value
  964. @param value
  965. """
  966. self.value = value
  967. self._setText()
  968. for direction in ('from', 'to'):
  969. for rel in self.GetRelations(direction):
  970. if direction == 'from':
  971. action = rel.GetTo()
  972. else:
  973. action = rel.GetFrom()
  974. task = GUI(show = None).ParseCommand(cmd = action.GetLog(string = False))
  975. task.set_param(rel.GetName(), self.value)
  976. action.SetParams(params = task.get_options())
  977. def GetPropDialog(self):
  978. """!Get properties dialog"""
  979. return self.propWin
  980. def SetPropDialog(self, win):
  981. """!Get properties dialog"""
  982. self.propWin = win
  983. def _setBrush(self):
  984. """!Set brush"""
  985. if self.prompt == 'raster':
  986. color = UserSettings.Get(group = 'modeler', key = 'data',
  987. subkey = ('color', 'raster'))
  988. elif self.prompt == 'raster3d':
  989. color = UserSettings.Get(group = 'modeler', key = 'data',
  990. subkey = ('color', 'raster3d'))
  991. elif self.prompt == 'vector':
  992. color = UserSettings.Get(group = 'modeler', key = 'data',
  993. subkey = ('color', 'vector'))
  994. else:
  995. color = UserSettings.Get(group = 'modeler', key = 'action',
  996. subkey = ('color', 'invalid'))
  997. wxColor = wx.Colour(color[0], color[1], color[2])
  998. self.SetBrush(wx.Brush(wxColor))
  999. def _setPen(self):
  1000. """!Set pen"""
  1001. isParameterized = False
  1002. for rel in self.GetRelations('from'):
  1003. if rel.GetTo().IsParameterized():
  1004. isParameterized = True
  1005. break
  1006. if not isParameterized:
  1007. for rel in self.GetRelations('to'):
  1008. if rel.GetFrom().IsParameterized():
  1009. isParameterized = True
  1010. break
  1011. if isParameterized:
  1012. width = int(UserSettings.Get(group = 'modeler', key = 'action',
  1013. subkey = ('width', 'parameterized')))
  1014. else:
  1015. width = int(UserSettings.Get(group = 'modeler', key = 'action',
  1016. subkey = ('width', 'default')))
  1017. pen = self.GetPen()
  1018. pen.SetWidth(width)
  1019. self.SetPen(pen)
  1020. def _setText(self):
  1021. """!Update text"""
  1022. self.ClearText()
  1023. name = []
  1024. for rel in self.GetRelations():
  1025. name.append(rel.GetName())
  1026. self.AddText('/'.join(name))
  1027. if self.value:
  1028. self.AddText(self.value)
  1029. else:
  1030. self.AddText(_('<not defined>'))
  1031. def Update(self):
  1032. """!Update action"""
  1033. self._setBrush()
  1034. self._setPen()
  1035. self._setText()
  1036. class ModelRelation(ogl.LineShape):
  1037. """!Data - action relation"""
  1038. def __init__(self, parent, fromShape, toShape, param = ''):
  1039. self.fromShape = fromShape
  1040. self.toShape = toShape
  1041. self.param = param
  1042. self.parent = parent
  1043. self._points = None
  1044. if self.parent.GetCanvas():
  1045. ogl.LineShape.__init__(self)
  1046. def __del__(self):
  1047. if self in self.fromShape.rels:
  1048. self.fromShape.rels.remove(self)
  1049. if self in self.toShape.rels:
  1050. self.toShape.rels.remove(self)
  1051. def GetFrom(self):
  1052. """!Get id of 'from' shape"""
  1053. return self.fromShape
  1054. def GetTo(self):
  1055. """!Get id of 'to' shape"""
  1056. return self.toShape
  1057. def GetData(self):
  1058. """!Get related ModelData instance
  1059. @return ModelData instance
  1060. @return None if not found
  1061. """
  1062. if isinstance(self.fromShape, ModelData):
  1063. return self.fromShape
  1064. elif isinstance(self.toShape, ModelData):
  1065. return self.toShape
  1066. return None
  1067. def GetName(self):
  1068. """!Get parameter name"""
  1069. return self.param
  1070. def ResetShapes(self):
  1071. """!Reset related objects"""
  1072. self.fromShape.ResetControlPoints()
  1073. self.toShape.ResetControlPoints()
  1074. self.ResetControlPoints()
  1075. def SetControlPoints(self, points):
  1076. """!Set control points"""
  1077. self._points = points
  1078. def GetControlPoints(self):
  1079. """!Get list of control points"""
  1080. return self._points
  1081. def _setPen(self):
  1082. """!Set pen"""
  1083. pen = self.GetPen()
  1084. pen.SetWidth(1)
  1085. pen.SetStyle(wx.SOLID)
  1086. self.SetPen(pen)
  1087. def OnDraw(self, dc):
  1088. """!Draw relation"""
  1089. self._setPen()
  1090. ogl.LineShape.OnDraw(self, dc)
  1091. def SetName(self, param):
  1092. self.param = param
  1093. class ModelItem(ModelObject):
  1094. def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
  1095. """!Abstract class for loops and conditions"""
  1096. ModelObject.__init__(self, id)
  1097. self.parent = parent
  1098. self.text = text
  1099. self.items = items # list of items in the loop
  1100. def GetText(self):
  1101. """!Get loop text"""
  1102. return self.text
  1103. def GetItems(self):
  1104. """!Get items (id)"""
  1105. return self.items
  1106. def SetId(self, id):
  1107. """!Set loop id"""
  1108. self.id = id
  1109. def SetText(self, cond):
  1110. """!Set loop text (condition)"""
  1111. self.text = cond
  1112. self.ClearText()
  1113. self.AddText('(' + str(self.id) + ') ' + self.text)
  1114. def GetLog(self):
  1115. """!Get log info"""
  1116. if self.text:
  1117. return _("Condition: ") + self.text
  1118. else:
  1119. return _("Condition: not defined")
  1120. def AddRelation(self, rel):
  1121. """!Record relation"""
  1122. self.rels.append(rel)
  1123. def Clear(self):
  1124. """!Clear object, remove rels"""
  1125. self.rels = list()
  1126. class ModelLoop(ModelItem, ogl.RectangleShape):
  1127. def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
  1128. """!Defines a loop"""
  1129. ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
  1130. if not width:
  1131. width = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'width'))
  1132. if not height:
  1133. height = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'height'))
  1134. if self.parent.GetCanvas():
  1135. ogl.RectangleShape.__init__(self, width, height)
  1136. self.SetCanvas(self.parent)
  1137. self.SetX(x)
  1138. self.SetY(y)
  1139. self.SetPen(wx.BLACK_PEN)
  1140. self.SetCornerRadius(100)
  1141. if text:
  1142. self.AddText('(' + str(self.id) + ') ' + text)
  1143. else:
  1144. self.AddText('(' + str(self.id) + ')')
  1145. self._setBrush()
  1146. def _setBrush(self):
  1147. """!Set brush"""
  1148. if not self.isEnabled:
  1149. color = UserSettings.Get(group='modeler', key='disabled',
  1150. subkey='color')
  1151. else:
  1152. color = UserSettings.Get(group='modeler', key='loop',
  1153. subkey=('color', 'valid'))
  1154. wxColor = wx.Colour(color[0], color[1], color[2])
  1155. self.SetBrush(wx.Brush(wxColor))
  1156. def Enable(self, enabled = True):
  1157. """!Enable/disable action"""
  1158. for item in self.items:
  1159. if not isinstance(item, ModelAction):
  1160. continue
  1161. item.Enable(enabled)
  1162. ModelObject.Enable(self, enabled)
  1163. def Update(self):
  1164. self._setBrush()
  1165. def GetName(self):
  1166. """!Get name"""
  1167. return _("loop")
  1168. def SetItems(self, items):
  1169. """!Set items (id)"""
  1170. self.items = items
  1171. def OnDraw(self, dc):
  1172. """!Draw loop in canvas"""
  1173. self._setBrush()
  1174. ogl.RectangleShape.Recentre(self, dc) # re-center text
  1175. ogl.RectangleShape.OnDraw(self, dc)
  1176. class ModelCondition(ModelItem, ogl.PolygonShape):
  1177. def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '',
  1178. items = { 'if' : [], 'else' : [] }):
  1179. """!Defines a if-else condition"""
  1180. ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
  1181. if not width:
  1182. self.width = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'width'))
  1183. else:
  1184. self.width = width
  1185. if not height:
  1186. self.height = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'height'))
  1187. else:
  1188. self.height = height
  1189. if self.parent.GetCanvas():
  1190. ogl.PolygonShape.__init__(self)
  1191. points = [(0, - self.height / 2),
  1192. (self.width / 2, 0),
  1193. (0, self.height / 2),
  1194. (- self.width / 2, 0)]
  1195. self.Create(points)
  1196. self.SetCanvas(self.parent)
  1197. self.SetX(x)
  1198. self.SetY(y)
  1199. self.SetPen(wx.BLACK_PEN)
  1200. if text:
  1201. self.AddText('(' + str(self.id) + ') ' + text)
  1202. else:
  1203. self.AddText('(' + str(self.id) + ')')
  1204. def GetName(self):
  1205. """!Get name"""
  1206. return _("if-else")
  1207. def GetWidth(self):
  1208. """!Get object width"""
  1209. return self.width
  1210. def GetHeight(self):
  1211. """!Get object height"""
  1212. return self.height
  1213. def SetItems(self, items, branch = 'if'):
  1214. """!Set items (id)
  1215. @param items list of items
  1216. @param branch 'if' / 'else'
  1217. """
  1218. if branch in ['if', 'else']:
  1219. self.items[branch] = items
  1220. class ProcessModelFile:
  1221. """!Process GRASS model file (gxm)"""
  1222. def __init__(self, tree):
  1223. """!A ElementTree handler for the GXM XML file, as defined in
  1224. grass-gxm.dtd.
  1225. """
  1226. self.tree = tree
  1227. self.root = self.tree.getroot()
  1228. # list of actions, data
  1229. self.properties = dict()
  1230. self.variables = dict()
  1231. self.actions = list()
  1232. self.data = list()
  1233. self.loops = list()
  1234. self.conditions = list()
  1235. self._processWindow()
  1236. self._processProperties()
  1237. self._processVariables()
  1238. self._processItems()
  1239. self._processData()
  1240. def _filterValue(self, value):
  1241. """!Filter value
  1242. @param value
  1243. """
  1244. value = value.replace('&lt;', '<')
  1245. value = value.replace('&gt;', '>')
  1246. return value
  1247. def _getNodeText(self, node, tag, default = ''):
  1248. """!Get node text"""
  1249. p = node.find(tag)
  1250. if p is not None:
  1251. if p.text:
  1252. return utils.normalize_whitespace(p.text)
  1253. else:
  1254. return ''
  1255. return default
  1256. def _processWindow(self):
  1257. """!Process window properties"""
  1258. node = self.root.find('window')
  1259. if node is None:
  1260. self.pos = self.size = None
  1261. return
  1262. self.pos, self.size = self._getDim(node)
  1263. def _processProperties(self):
  1264. """!Process model properties"""
  1265. node = self.root.find('properties')
  1266. if node is None:
  1267. return
  1268. for key in ('name', 'description', 'author'):
  1269. self._processProperty(node, key)
  1270. for f in node.findall('flag'):
  1271. name = f.get('name', '')
  1272. if name == 'overwrite':
  1273. self.properties['overwrite'] = True
  1274. def _processProperty(self, pnode, name):
  1275. """!Process given property"""
  1276. node = pnode.find(name)
  1277. if node is not None:
  1278. self.properties[name] = node.text
  1279. else:
  1280. self.properties[name] = ''
  1281. def _processVariables(self):
  1282. """!Process model variables"""
  1283. vnode = self.root.find('variables')
  1284. if vnode is None:
  1285. return
  1286. for node in vnode.findall('variable'):
  1287. name = node.get('name', '')
  1288. if not name:
  1289. continue # should not happen
  1290. self.variables[name] = { 'type' : node.get('type', 'string') }
  1291. for key in ('description', 'value'):
  1292. self._processVariable(node, name, key)
  1293. def _processVariable(self, pnode, name, key):
  1294. """!Process given variable"""
  1295. node = pnode.find(key)
  1296. if node is not None:
  1297. if node.text:
  1298. self.variables[name][key] = node.text
  1299. def _processItems(self):
  1300. """!Process model items (actions, loops, conditions)"""
  1301. self._processActions()
  1302. self._processLoops()
  1303. self._processConditions()
  1304. def _processActions(self):
  1305. """!Process model file"""
  1306. for action in self.root.findall('action'):
  1307. pos, size = self._getDim(action)
  1308. disabled = False
  1309. task = action.find('task')
  1310. if task is not None:
  1311. if task.find('disabled') is not None:
  1312. disabled = True
  1313. task = self._processTask(task)
  1314. else:
  1315. task = None
  1316. aId = int(action.get('id', -1))
  1317. self.actions.append({ 'pos' : pos,
  1318. 'size' : size,
  1319. 'task' : task,
  1320. 'id' : aId,
  1321. 'disabled' : disabled })
  1322. def _getDim(self, node):
  1323. """!Get position and size of shape"""
  1324. pos = size = None
  1325. posAttr = node.get('pos', None)
  1326. if posAttr:
  1327. posVal = map(int, posAttr.split(','))
  1328. try:
  1329. pos = (posVal[0], posVal[1])
  1330. except:
  1331. pos = None
  1332. sizeAttr = node.get('size', None)
  1333. if sizeAttr:
  1334. sizeVal = map(int, sizeAttr.split(','))
  1335. try:
  1336. size = (sizeVal[0], sizeVal[1])
  1337. except:
  1338. size = None
  1339. return pos, size
  1340. def _processData(self):
  1341. """!Process model file"""
  1342. for data in self.root.findall('data'):
  1343. pos, size = self._getDim(data)
  1344. param = data.find('data-parameter')
  1345. prompt = value = None
  1346. if param is not None:
  1347. prompt = param.get('prompt', None)
  1348. value = self._filterValue(self._getNodeText(param, 'value'))
  1349. if data.find('intermediate') is None:
  1350. intermediate = False
  1351. else:
  1352. intermediate = True
  1353. rels = list()
  1354. for rel in data.findall('relation'):
  1355. defrel = { 'id' : int(rel.get('id', -1)),
  1356. 'dir' : rel.get('dir', 'to'),
  1357. 'name' : rel.get('name', '') }
  1358. points = list()
  1359. for point in rel.findall('point'):
  1360. x = self._filterValue(self._getNodeText(point, 'x'))
  1361. y = self._filterValue(self._getNodeText(point, 'y'))
  1362. points.append((float(x), float(y)))
  1363. defrel['points'] = points
  1364. rels.append(defrel)
  1365. self.data.append({ 'pos' : pos,
  1366. 'size': size,
  1367. 'prompt' : prompt,
  1368. 'value' : value,
  1369. 'intermediate' : intermediate,
  1370. 'rels' : rels })
  1371. def _processTask(self, node):
  1372. """!Process task
  1373. @return grassTask instance
  1374. @return None on error
  1375. """
  1376. cmd = list()
  1377. parameterized = list()
  1378. name = node.get('name', None)
  1379. if not name:
  1380. return None
  1381. cmd.append(name)
  1382. # flags
  1383. for f in node.findall('flag'):
  1384. flag = f.get('name', '')
  1385. if f.get('parameterized', '0') == '1':
  1386. parameterized.append(('flag', flag))
  1387. if f.get('value', '1') == '0':
  1388. continue
  1389. if len(flag) > 1:
  1390. cmd.append('--' + flag)
  1391. else:
  1392. cmd.append('-' + flag)
  1393. # parameters
  1394. for p in node.findall('parameter'):
  1395. name = p.get('name', '')
  1396. if p.find('parameterized') is not None:
  1397. parameterized.append(('param', name))
  1398. cmd.append('%s=%s' % (name,
  1399. self._filterValue(self._getNodeText(p, 'value'))))
  1400. task, err = GUI(show = None, checkError = True).ParseCommand(cmd = cmd)
  1401. if err:
  1402. GWarning(os.linesep.join(err))
  1403. for opt, name in parameterized:
  1404. if opt == 'flag':
  1405. task.set_flag(name, True, element = 'parameterized')
  1406. else:
  1407. task.set_param(name, True, element = 'parameterized')
  1408. return task
  1409. def _processLoops(self):
  1410. """!Process model loops"""
  1411. for node in self.root.findall('loop'):
  1412. pos, size = self._getDim(node)
  1413. text = self._filterValue(self._getNodeText(node, 'condition')).strip()
  1414. aid = list()
  1415. for anode in node.findall('item'):
  1416. try:
  1417. aid.append(int(anode.text))
  1418. except ValueError:
  1419. pass
  1420. self.loops.append({ 'pos' : pos,
  1421. 'size' : size,
  1422. 'text' : text,
  1423. 'id' : int(node.get('id', -1)),
  1424. 'items' : aid })
  1425. def _processConditions(self):
  1426. """!Process model conditions"""
  1427. for node in self.root.findall('if-else'):
  1428. pos, size = self._getDim(node)
  1429. text = self._filterValue(self._getNodeText(node, 'condition')).strip()
  1430. aid = { 'if' : list(),
  1431. 'else' : list() }
  1432. for b in aid.keys():
  1433. bnode = node.find(b)
  1434. if bnode is None:
  1435. continue
  1436. for anode in bnode.findall('item'):
  1437. try:
  1438. aid[b].append(int(anode.text))
  1439. except ValueError:
  1440. pass
  1441. self.conditions.append({ 'pos' : pos,
  1442. 'size' : size,
  1443. 'text' : text,
  1444. 'id' : int(node.get('id', -1)),
  1445. 'items' : aid })
  1446. class WriteModelFile:
  1447. """!Generic class for writing model file"""
  1448. def __init__(self, fd, model):
  1449. self.fd = fd
  1450. self.model = model
  1451. self.properties = model.GetProperties()
  1452. self.variables = model.GetVariables()
  1453. self.items = model.GetItems()
  1454. self.indent = 0
  1455. self._header()
  1456. self._window()
  1457. self._properties()
  1458. self._variables()
  1459. self._items()
  1460. dataList = list()
  1461. for action in model.GetItems(objType = ModelAction):
  1462. for rel in action.GetRelations():
  1463. dataItem = rel.GetData()
  1464. if dataItem not in dataList:
  1465. dataList.append(dataItem)
  1466. self._data(dataList)
  1467. self._footer()
  1468. def _filterValue(self, value):
  1469. """!Make value XML-valid"""
  1470. value = value.replace('<', '&lt;')
  1471. value = value.replace('>', '&gt;')
  1472. return value
  1473. def _header(self):
  1474. """!Write header"""
  1475. self.fd.write('<?xml version="1.0" encoding="%s"?>\n' % GetDefaultEncoding(forceUTF8 = True))
  1476. self.fd.write('<!DOCTYPE gxm SYSTEM "grass-gxm.dtd">\n')
  1477. self.fd.write('%s<gxm>\n' % (' ' * self.indent))
  1478. self.indent += 4
  1479. def _footer(self):
  1480. """!Write footer"""
  1481. self.indent -= 4
  1482. self.fd.write('%s</gxm>\n' % (' ' * self.indent))
  1483. def _window(self):
  1484. """!Write window properties"""
  1485. canvas = self.model.GetCanvas()
  1486. if canvas is None:
  1487. return
  1488. win = canvas.parent
  1489. pos = win.GetPosition()
  1490. size = win.GetSize()
  1491. self.fd.write('%s<window pos="%d,%d" size="%d,%d" />\n' % \
  1492. (' ' * self.indent, pos[0], pos[1], size[0], size[1]))
  1493. def _properties(self):
  1494. """!Write model properties"""
  1495. self.fd.write('%s<properties>\n' % (' ' * self.indent))
  1496. self.indent += 4
  1497. if self.properties['name']:
  1498. self.fd.write('%s<name>%s</name>\n' % (' ' * self.indent, EncodeString(self.properties['name'])))
  1499. if self.properties['description']:
  1500. self.fd.write('%s<description>%s</description>\n' % (' ' * self.indent,
  1501. EncodeString(self.properties['description'])))
  1502. if self.properties['author']:
  1503. self.fd.write('%s<author>%s</author>\n' % (' ' * self.indent,
  1504. EncodeString(self.properties['author'])))
  1505. if 'overwrite' in self.properties and \
  1506. self.properties['overwrite']:
  1507. self.fd.write('%s<flag name="overwrite" />\n' % (' ' * self.indent))
  1508. self.indent -= 4
  1509. self.fd.write('%s</properties>\n' % (' ' * self.indent))
  1510. def _variables(self):
  1511. """!Write model variables"""
  1512. if not self.variables:
  1513. return
  1514. self.fd.write('%s<variables>\n' % (' ' * self.indent))
  1515. self.indent += 4
  1516. for name, values in self.variables.iteritems():
  1517. self.fd.write('%s<variable name="%s" type="%s">\n' % \
  1518. (' ' * self.indent, EncodeString(name), values['type']))
  1519. self.indent += 4
  1520. if 'value' in values:
  1521. self.fd.write('%s<value>%s</value>\n' % \
  1522. (' ' * self.indent, EncodeString(values['value'])))
  1523. if 'description' in values:
  1524. self.fd.write('%s<description>%s</description>\n' % \
  1525. (' ' * self.indent, EncodeString(values['description'])))
  1526. self.indent -= 4
  1527. self.fd.write('%s</variable>\n' % (' ' * self.indent))
  1528. self.indent -= 4
  1529. self.fd.write('%s</variables>\n' % (' ' * self.indent))
  1530. def _items(self):
  1531. """!Write actions/loops/conditions"""
  1532. for item in self.items:
  1533. if isinstance(item, ModelAction):
  1534. self._action(item)
  1535. elif isinstance(item, ModelLoop):
  1536. self._loop(item)
  1537. elif isinstance(item, ModelCondition):
  1538. self._condition(item)
  1539. def _action(self, action):
  1540. """!Write actions"""
  1541. self.fd.write('%s<action id="%d" name="%s" pos="%d,%d" size="%d,%d">\n' % \
  1542. (' ' * self.indent, action.GetId(), action.GetName(), action.GetX(), action.GetY(),
  1543. action.GetWidth(), action.GetHeight()))
  1544. self.indent += 4
  1545. self.fd.write('%s<task name="%s">\n' % (' ' * self.indent, action.GetLog(string = False)[0]))
  1546. self.indent += 4
  1547. if not action.IsEnabled():
  1548. self.fd.write('%s<disabled />\n' % (' ' * self.indent))
  1549. for key, val in action.GetParams().iteritems():
  1550. if key == 'flags':
  1551. for f in val:
  1552. if f.get('value', False) or f.get('parameterized', False):
  1553. if f.get('parameterized', False):
  1554. if f.get('value', False) == False:
  1555. self.fd.write('%s<flag name="%s" value="0" parameterized="1" />\n' %
  1556. (' ' * self.indent, f.get('name', '')))
  1557. else:
  1558. self.fd.write('%s<flag name="%s" parameterized="1" />\n' %
  1559. (' ' * self.indent, f.get('name', '')))
  1560. else:
  1561. self.fd.write('%s<flag name="%s" />\n' %
  1562. (' ' * self.indent, f.get('name', '')))
  1563. else: # parameter
  1564. for p in val:
  1565. if not p.get('value', '') and not p.get('parameterized', False):
  1566. continue
  1567. self.fd.write('%s<parameter name="%s">\n' %
  1568. (' ' * self.indent, p.get('name', '')))
  1569. self.indent += 4
  1570. if p.get('parameterized', False):
  1571. self.fd.write('%s<parameterized />\n' % (' ' * self.indent))
  1572. self.fd.write('%s<value>%s</value>\n' %
  1573. (' ' * self.indent, self._filterValue(p.get('value', ''))))
  1574. self.indent -= 4
  1575. self.fd.write('%s</parameter>\n' % (' ' * self.indent))
  1576. self.indent -= 4
  1577. self.fd.write('%s</task>\n' % (' ' * self.indent))
  1578. self.indent -= 4
  1579. self.fd.write('%s</action>\n' % (' ' * self.indent))
  1580. def _data(self, dataList):
  1581. """!Write data"""
  1582. for data in dataList:
  1583. self.fd.write('%s<data pos="%d,%d" size="%d,%d">\n' % \
  1584. (' ' * self.indent, data.GetX(), data.GetY(),
  1585. data.GetWidth(), data.GetHeight()))
  1586. self.indent += 4
  1587. self.fd.write('%s<data-parameter prompt="%s">\n' % \
  1588. (' ' * self.indent, data.GetPrompt()))
  1589. self.indent += 4
  1590. self.fd.write('%s<value>%s</value>\n' %
  1591. (' ' * self.indent, self._filterValue(data.GetValue())))
  1592. self.indent -= 4
  1593. self.fd.write('%s</data-parameter>\n' % (' ' * self.indent))
  1594. if data.IsIntermediate():
  1595. self.fd.write('%s<intermediate />\n' % (' ' * self.indent))
  1596. # relations
  1597. for ft in ('from', 'to'):
  1598. for rel in data.GetRelations(ft):
  1599. if ft == 'from':
  1600. aid = rel.GetTo().GetId()
  1601. else:
  1602. aid = rel.GetFrom().GetId()
  1603. self.fd.write('%s<relation dir="%s" id="%d" name="%s">\n' % \
  1604. (' ' * self.indent, ft, aid, rel.GetName()))
  1605. self.indent += 4
  1606. for point in rel.GetLineControlPoints()[1:-1]:
  1607. self.fd.write('%s<point>\n' % (' ' * self.indent))
  1608. self.indent += 4
  1609. x, y = point.Get()
  1610. self.fd.write('%s<x>%d</x>\n' % (' ' * self.indent, int(x)))
  1611. self.fd.write('%s<y>%d</y>\n' % (' ' * self.indent, int(y)))
  1612. self.indent -= 4
  1613. self.fd.write('%s</point>\n' % (' ' * self.indent))
  1614. self.indent -= 4
  1615. self.fd.write('%s</relation>\n' % (' ' * self.indent))
  1616. self.indent -= 4
  1617. self.fd.write('%s</data>\n' % (' ' * self.indent))
  1618. def _loop(self, loop):
  1619. """!Write loops"""
  1620. self.fd.write('%s<loop id="%d" pos="%d,%d" size="%d,%d">\n' % \
  1621. (' ' * self.indent, loop.GetId(), loop.GetX(), loop.GetY(),
  1622. loop.GetWidth(), loop.GetHeight()))
  1623. text = loop.GetText()
  1624. self.indent += 4
  1625. if text:
  1626. self.fd.write('%s<condition>%s</condition>\n' %
  1627. (' ' * self.indent, self._filterValue(text)))
  1628. for item in loop.GetItems():
  1629. self.fd.write('%s<item>%d</item>\n' %
  1630. (' ' * self.indent, item.GetId()))
  1631. self.indent -= 4
  1632. self.fd.write('%s</loop>\n' % (' ' * self.indent))
  1633. def _condition(self, condition):
  1634. """!Write conditions"""
  1635. bbox = condition.GetBoundingBoxMin()
  1636. self.fd.write('%s<if-else id="%d" pos="%d,%d" size="%d,%d">\n' % \
  1637. (' ' * self.indent, condition.GetId(), condition.GetX(), condition.GetY(),
  1638. bbox[0], bbox[1]))
  1639. text = condition.GetText()
  1640. self.indent += 4
  1641. if text:
  1642. self.fd.write('%s<condition>%s</condition>\n' %
  1643. (' ' * self.indent, self._filterValue(text)))
  1644. items = condition.GetItems()
  1645. for b in items.keys():
  1646. if len(items[b]) < 1:
  1647. continue
  1648. self.fd.write('%s<%s>\n' % (' ' * self.indent, b))
  1649. self.indent += 4
  1650. for item in items[b]:
  1651. self.fd.write('%s<item>%d</item>\n' %
  1652. (' ' * self.indent, item.GetId()))
  1653. self.indent -= 4
  1654. self.fd.write('%s</%s>\n' % (' ' * self.indent, b))
  1655. self.indent -= 4
  1656. self.fd.write('%s</if-else>\n' % (' ' * self.indent))
  1657. class WritePythonFile:
  1658. def __init__(self, fd, model):
  1659. """!Class for exporting model to Python script
  1660. @param fd file desciptor
  1661. """
  1662. self.fd = fd
  1663. self.model = model
  1664. self.indent = 4
  1665. self._writePython()
  1666. def _writePython(self):
  1667. """!Write model to file"""
  1668. properties = self.model.GetProperties()
  1669. self.fd.write(
  1670. r"""#!/usr/bin/env python
  1671. #
  1672. #%s
  1673. #
  1674. # MODULE: %s
  1675. #
  1676. # AUTHOR(S): %s
  1677. #
  1678. # PURPOSE: %s
  1679. #
  1680. # DATE: %s
  1681. #
  1682. #%s
  1683. """ % ('#' * 77,
  1684. EncodeString(properties['name']),
  1685. EncodeString(properties['author']),
  1686. EncodeString('\n# '.join(properties['description'].splitlines())),
  1687. time.asctime(),
  1688. '#' * 77))
  1689. self.fd.write(
  1690. r"""
  1691. import sys
  1692. import os
  1693. import atexit
  1694. import grass.script as grass
  1695. """)
  1696. # cleanup()
  1697. rast, vect, rast3d, msg = self.model.GetIntermediateData()
  1698. self.fd.write(
  1699. r"""
  1700. def cleanup():
  1701. """)
  1702. if rast:
  1703. self.fd.write(
  1704. r""" grass.run_command('g.remove',
  1705. rast=%s)
  1706. """ % ','.join(map(lambda x: "'" + x + "'", rast)))
  1707. if vect:
  1708. self.fd.write(
  1709. r""" grass.run_command('g.remove',
  1710. vect = %s)
  1711. """ % ','.join(map(lambda x: "'" + x + "'", vect)))
  1712. if rast3d:
  1713. self.fd.write(
  1714. r""" grass.run_command('g.remove',
  1715. rast3d = %s)
  1716. """ % ','.join(map(lambda x: "'" + x + "'", rast3d)))
  1717. if not rast and not vect and not rast3d:
  1718. self.fd.write(' pass\n')
  1719. self.fd.write("\ndef main():\n")
  1720. for item in self.model.GetItems():
  1721. self._writePythonItem(item)
  1722. self.fd.write("\n return 0\n")
  1723. self.fd.write(
  1724. r"""
  1725. if __name__ == "__main__":
  1726. options, flags = grass.parser()
  1727. atexit.register(cleanup)
  1728. sys.exit(main())
  1729. """)
  1730. def _writePythonItem(self, item, ignoreBlock = True, variables = []):
  1731. """!Write model object to Python file"""
  1732. if isinstance(item, ModelAction):
  1733. if ignoreBlock and item.GetBlockId(): # ignore items in loops of conditions
  1734. return
  1735. self._writePythonAction(item, variables = variables)
  1736. elif isinstance(item, ModelLoop) or isinstance(item, ModelCondition):
  1737. # substitute condition
  1738. variables = self.model.GetVariables()
  1739. cond = item.GetText()
  1740. for variable in variables:
  1741. pattern = re.compile('%' + variable)
  1742. if pattern.search(cond):
  1743. value = variables[variable].get('value', '')
  1744. if variables[variable].get('type', 'string') == 'string':
  1745. value = '"' + value + '"'
  1746. cond = pattern.sub(value, cond)
  1747. if isinstance(item, ModelLoop):
  1748. condVar, condText = map(lambda x: x.strip(), re.split('\s*in\s*', cond))
  1749. cond = "%sfor %s in " % (' ' * self.indent, condVar)
  1750. if condText[0] == '`' and condText[-1] == '`':
  1751. task = GUI(show = None).ParseCommand(cmd = utils.split(condText[1:-1]))
  1752. cond += "grass.read_command("
  1753. cond += self._getPythonActionCmd(task, len(cond), variables = [condVar]) + ".splitlines()"
  1754. else:
  1755. cond += condText
  1756. self.fd.write('%s:\n' % cond)
  1757. self.indent += 4
  1758. for action in item.GetItems():
  1759. self._writePythonItem(action, ignoreBlock = False, variables = [condVar])
  1760. self.indent -= 4
  1761. else: # ModelCondition
  1762. self.fd.write('%sif %s:\n' % (' ' * self.indent, cond))
  1763. self.indent += 4
  1764. condItems = item.GetItems()
  1765. for action in condItems['if']:
  1766. self._writePythonItem(action, ignoreBlock = False)
  1767. if condItems['else']:
  1768. self.indent -= 4
  1769. self.fd.write('%selse:\n' % (' ' * self.indent))
  1770. self.indent += 4
  1771. for action in condItems['else']:
  1772. self._writePythonItem(action, ignoreBlock = False)
  1773. self.indent += 4
  1774. def _writePythonAction(self, item, variables = []):
  1775. """!Write model action to Python file"""
  1776. task = GUI(show = None).ParseCommand(cmd = item.GetLog(string = False, substitute = self.model.GetVariables()))
  1777. strcmd = "%sgrass.run_command(" % (' ' * self.indent)
  1778. self.fd.write(strcmd + self._getPythonActionCmd(task, len(strcmd), variables) + '\n')
  1779. def _getPythonActionCmd(self, task, cmdIndent, variables = []):
  1780. opts = task.get_options()
  1781. ret = ''
  1782. flags = ''
  1783. params = list()
  1784. for f in opts['flags']:
  1785. if f.get('value', False):
  1786. name = f.get('name', '')
  1787. if len(name) > 1:
  1788. params.append('%s = True' % name)
  1789. else:
  1790. flags += name
  1791. for p in opts['params']:
  1792. name = p.get('name', None)
  1793. value = p.get('value', None)
  1794. if name and value:
  1795. ptype = p.get('type', 'string')
  1796. if value[0] == '%':
  1797. params.append("%s = %s" % (name, value[1:]))
  1798. elif ptype == 'string':
  1799. params.append('%s = "%s"' % (name, value))
  1800. else:
  1801. params.append("%s = %s" % (name, value))
  1802. ret += '"%s"' % task.get_name()
  1803. if flags:
  1804. ret += ",\n%sflags = '%s'" % (' ' * cmdIndent, flags)
  1805. if len(params) > 0:
  1806. ret += ",\n"
  1807. for opt in params[:-1]:
  1808. ret += "%s%s,\n" % (' ' * cmdIndent, opt)
  1809. ret += "%s%s)" % (' ' * cmdIndent, params[-1])
  1810. else:
  1811. ret += ")"
  1812. return ret
  1813. class ModelParamDialog(wx.Dialog):
  1814. def __init__(self, parent, params, id = wx.ID_ANY, title = _("Model parameters"),
  1815. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
  1816. """!Model parameters dialog
  1817. """
  1818. self.parent = parent
  1819. self.params = params
  1820. self.tasks = list() # list of tasks/pages
  1821. wx.Dialog.__init__(self, parent = parent, id = id, title = title, style = style, **kwargs)
  1822. self.notebook = GNotebook(parent = self,
  1823. style = globalvar.FNPageDStyle)
  1824. panel = self._createPages()
  1825. wx.CallAfter(self.notebook.SetSelection, 0)
  1826. # intermediate data?
  1827. self.interData = wx.CheckBox(parent = self, label = _("Delete intermediate data when finish"))
  1828. self.interData.SetValue(True)
  1829. rast, vect, rast3d, msg = self.parent.GetModel().GetIntermediateData()
  1830. if not rast and not vect and not rast3d:
  1831. self.interData.Hide()
  1832. self.btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
  1833. self.btnRun = wx.Button(parent = self, id = wx.ID_OK,
  1834. label = _("&Run"))
  1835. self.btnRun.SetDefault()
  1836. self._layout()
  1837. size = self.GetBestSize()
  1838. self.SetMinSize(size)
  1839. self.SetSize((size.width, size.height +
  1840. panel.constrained_size[1] -
  1841. panel.panelMinHeight))
  1842. def _layout(self):
  1843. btnSizer = wx.StdDialogButtonSizer()
  1844. btnSizer.AddButton(self.btnCancel)
  1845. btnSizer.AddButton(self.btnRun)
  1846. btnSizer.Realize()
  1847. mainSizer = wx.BoxSizer(wx.VERTICAL)
  1848. mainSizer.Add(item = self.notebook, proportion = 1,
  1849. flag = wx.EXPAND)
  1850. if self.interData.IsShown():
  1851. mainSizer.Add(item = self.interData, proportion = 0,
  1852. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  1853. mainSizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
  1854. style = wx.LI_HORIZONTAL),
  1855. proportion = 0,
  1856. flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
  1857. mainSizer.Add(item = btnSizer, proportion = 0,
  1858. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  1859. self.SetSizer(mainSizer)
  1860. mainSizer.Fit(self)
  1861. def _createPages(self):
  1862. """!Create for each parameterized module its own page"""
  1863. nameOrdered = [''] * len(self.params.keys())
  1864. for name, params in self.params.iteritems():
  1865. nameOrdered[params['idx']] = name
  1866. for name in nameOrdered:
  1867. params = self.params[name]
  1868. panel = self._createPage(name, params)
  1869. if name == 'variables':
  1870. name = _('Variables')
  1871. self.notebook.AddPage(page = panel, text = name)
  1872. return panel
  1873. def _createPage(self, name, params):
  1874. """!Define notebook page"""
  1875. if name in globalvar.grassCmd:
  1876. task = gtask.grassTask(name)
  1877. else:
  1878. task = gtask.grassTask()
  1879. task.flags = params['flags']
  1880. task.params = params['params']
  1881. panel = CmdPanel(parent = self, id = wx.ID_ANY, task = task)
  1882. self.tasks.append(task)
  1883. return panel
  1884. def GetErrors(self):
  1885. """!Check for errors, get list of messages"""
  1886. errList = list()
  1887. for task in self.tasks:
  1888. errList += task.get_cmd_error()
  1889. return errList
  1890. def DeleteIntermediateData(self):
  1891. """!Check if to detele intermediate data"""
  1892. if self.interData.IsShown() and self.interData.IsChecked():
  1893. return True
  1894. return False