4 @brief wxGUI Graphical Modeler for creating, editing, and managing models
33 - ModelConditionDialog
36 (C) 2010-2011 by the GRASS Development Team
37 This program is free software under the GNU General Public License
38 (>=v2). Read the file COPYING that comes with GRASS for details.
40 @author Martin Landa <landa.martin gmail.com>
55 import xml.etree.ElementTree
as etree
57 import elementtree.ElementTree
as etree
61 import wx.lib.ogl
as ogl
62 import wx.lib.flatnotebook
as FN
63 import wx.lib.colourselect
as csel
64 import wx.lib.mixins.listctrl
as listmix
74 from debug
import Debug
75 from gcmd
import GMessage, GException, GWarning, GError, RunCommand
76 from gdialogs
import ElementDialog, GetImageHandlers
77 from preferences
import PreferencesBaseDialog, globalSettings
as UserSettings
78 from ghelp
import SearchModuleWindow
84 """!Class representing the model"""
90 'description' : _(
"Script generated by wxGUI Graphical Modeler."),
91 'author' : getpass.getuser() }
99 """!Get canvas or None"""
103 """!Get list of model items
105 @param objType Object type to filter model objects
111 for item
in self.
items:
112 if isinstance(item, objType):
118 """!Get item of given id
122 @return Model* instance
123 @return None if no item found
127 if item.GetId() == aId:
133 """!Get number of items"""
135 return len(self.
GetItems(objType = ModelAction))
140 """!Get next id (data ignored)
142 @return next id to be used (default: 1)
144 if len(self.
items) < 1:
147 currId = self.
items[-1].GetId()
154 """!Get model properties"""
158 """!Get model variables"""
165 """!Set model variables"""
173 """!Remove item from model
175 @return list of related items to remove/update
180 if not isinstance(item, ModelData):
181 self.items.remove(item)
183 if isinstance(item, ModelAction):
184 for rel
in item.GetRelations():
187 if len(data.GetRelations()) < 2:
192 elif isinstance(item, ModelData):
193 for rel
in item.GetRelations():
195 if rel.GetFrom() == self:
196 relList.append(rel.GetTo())
198 relList.append(rel.GetFrom())
200 elif isinstance(item, ModelLoop):
201 for rel
in item.GetRelations():
204 action.UnSetBlock(item)
206 return relList, upList
209 """!Find action by id"""
210 alist = self.
GetItems(objType = ModelAction)
212 if action.GetId() == aId:
218 """!Get list of data items"""
220 dataItems = self.
GetItems(objType = ModelData)
222 for action
in self.
GetItems(objType = ModelAction):
223 for rel
in action.GetRelations():
224 dataItem = rel.GetData()
225 if dataItem
not in result:
226 result.append(dataItem)
227 if dataItem
in dataItems:
228 dataItems.remove(dataItem)
237 """!Find data item in the model
242 @return ModelData instance
243 @return None if not found
246 if data.GetValue() == value
and \
247 data.GetPrompt() == prompt:
253 """!Load model definition stored in GRASS Model XML file (gxm)
255 @todo Validate against DTD
257 Raise exception on error.
259 dtdFilename = os.path.join(globalvar.ETCWXDIR,
"xml",
"grass-gxm.dtd")
264 except StandardError, e:
268 win = self.canvas.parent
270 win.SetPosition(gxmXml.pos)
272 win.SetSize(gxmXml.size)
279 for action
in gxmXml.actions:
281 x = action[
'pos'][0],
282 y = action[
'pos'][1],
283 width = action[
'size'][0],
284 height = action[
'size'][1],
285 task = action[
'task'],
288 if action[
'disabled']:
289 actionItem.Enable(
False)
293 task = actionItem.GetTask()
294 parameterized =
False
296 for f
in task.get_options()[
'flags']:
297 if f.get(
'parameterized',
False):
300 for p
in task.get_options()[
'params']:
301 if p.get(
'required',
'no') !=
'no' and \
302 p.get(
'value',
'') ==
'' and \
303 p.get(
'default',
'') ==
'':
305 if p.get(
'parameterized',
False):
308 actionItem.SetValid(valid)
309 actionItem.SetParameterized(parameterized)
313 for data
in gxmXml.data:
317 width = data[
'size'][0],
318 height = data[
'size'][1],
319 prompt = data[
'prompt'],
320 value = data[
'value'])
321 dataItem.SetIntermediate(data[
'intermediate'])
323 for rel
in data[
'rels']:
325 if rel[
'dir'] ==
'from':
326 relation =
ModelRelation(parent = self, fromShape = dataItem,
327 toShape = actionItem, param = rel[
'name'])
329 relation =
ModelRelation(parent = self, fromShape = actionItem,
330 toShape = dataItem, param = rel[
'name'])
331 relation.SetControlPoints(rel[
'points'])
332 actionItem.AddRelation(relation)
333 dataItem.AddRelation(relation)
339 for loop
in gxmXml.loops:
343 width = loop[
'size'][0],
344 height = loop[
'size'][1],
350 for condition
in gxmXml.conditions:
352 x = condition[
'pos'][0],
353 y = condition[
'pos'][1],
354 width = condition[
'size'][0],
355 height = condition[
'size'][1],
356 text = condition[
'text'],
357 id = condition[
'id'])
361 for loop
in gxmXml.loops:
363 for aId
in loop[
'items']:
367 loopItem = self.
GetItem(loop[
'id'])
368 loopItem.SetItems(alist)
370 for action
in loopItem.GetItems():
371 action.SetBlock(loopItem)
373 for condition
in gxmXml.conditions:
374 conditionItem = self.
GetItem(condition[
'id'])
375 for b
in condition[
'items'].keys():
377 for aId
in condition[
'items'][b]:
380 conditionItem.SetItems(alist, branch = b)
382 items = conditionItem.GetItems()
383 for b
in items.keys():
384 for action
in items[b]:
385 action.SetBlock(conditionItem)
388 """!Add item to the list"""
389 iId = newItem.GetId()
392 for item
in self.
items:
393 if item.GetId() > iId:
394 self.items.insert(i, newItem)
398 self.items.append(newItem)
401 """Return True if model is valid"""
408 """!Validate model, return None if model is valid otherwise
411 for action
in self.
GetItems(objType = ModelAction):
412 task =
menuform.GUI(show =
None).ParseCommand(cmd = action.GetLog(string =
False))
413 errList += task.getCmdError()
417 def RunAction(self, item, params, log, onDone, statusbar = None):
420 @param item action item
421 @param params parameters dict
422 @param log logging window
423 @param onDone on-done method
424 @param statusbar wx.StatusBar instance or None
426 name = item.GetName()
428 paramsOrig = item.GetParams(dcopy =
True)
429 item.MergeParams(params[name])
432 statusbar.SetStatusText(_(
'Running model...'), 0)
433 log.RunCmd(command = item.GetLog(string =
False),
437 item.SetParams(paramsOrig)
439 def Run(self, log, onDone, parent = None):
442 @param log logging window (see goutput.GMConsole)
443 @param onDone on-done method
444 @param parent window for messages or None
447 GMessage(parent = parent,
448 message = _(
'Model is empty. Nothing to run.'))
452 if isinstance(parent, wx.Frame):
453 statusbar = parent.GetStatusBar()
457 statusbar.SetStatusText(_(
'Validating model...'), 0)
460 statusbar.SetStatusText(
'', 0)
462 dlg = wx.MessageDialog(parent = parent,
463 message = _(
'Model is not valid. Do you want to '
464 'run the model anyway?\n\n%s') %
'\n'.join(errList),
465 caption = _(
"Run model?"),
466 style = wx.YES_NO | wx.NO_DEFAULT |
467 wx.ICON_QUESTION | wx.CENTRE)
468 ret = dlg.ShowModal()
479 ret = dlg.ShowModal()
484 err = dlg.GetErrors()
486 GError(parent = self, message = unicode(
'\n'.join(err)))
489 log.cmdThread.SetId(-1)
491 if not item.IsEnabled():
493 if isinstance(item, ModelAction):
494 if item.GetBlockId():
496 self.
RunAction(item, params, log, onDone)
497 elif isinstance(item, ModelLoop):
498 cond = item.GetText()
501 for variable
in variables:
502 pattern = re.compile(
'%' + variable)
503 if pattern.search(cond):
504 value = variables[variable].get(
'value',
'')
505 vtype = variables[variable].get(
'type',
'string')
506 if vtype ==
'string':
507 value =
'"' + value +
'"'
508 cond = pattern.sub(value, cond)
510 condVar, condText = re.split(
'\s*in\s*', cond)
512 for action
in item.GetItems():
513 for vars()[condVar]
in eval(condText):
514 if not isinstance(action, ModelAction)
or \
515 not action.IsEnabled():
518 self.
RunAction(action, params, log, onDone)
524 """!Detele intermediate data"""
528 log.RunCmd([
'g.remove',
'rast=%s' %
','.join(rast)])
530 log.RunCmd([
'g.remove',
'rast3d=%s' %
','.join(rast3d)])
532 log.RunCmd([
'g.remove',
'vect=%s' %
','.join(vect)])
535 """!Get info about intermediate data"""
540 if not data.IsIntermediate():
542 name = data.GetValue()
543 prompt = data.GetPrompt()
544 if prompt ==
'raster':
546 elif prompt ==
'vector':
548 elif prompt ==
'rast3d':
553 msg +=
'\n\n%s: ' % _(
'Raster maps')
554 msg +=
', '.join(rast)
556 msg +=
'\n\n%s: ' % _(
'3D raster maps')
557 msg +=
', '.join(rast3d)
559 msg +=
'\n\n%s: ' % _(
'Vector maps')
560 msg +=
', '.join(vect)
562 return rast, vect, rast3d, msg
566 for item
in self.
items:
570 """!Return True if model is parameterized"""
577 """!Return parameterized options"""
582 result[_(
"Variables")] = {
'flags' : list(),
585 for name, values
in self.variables.iteritems():
586 gtype = values.get(
'type',
'string')
587 if gtype
in (
'raster',
'vector'):
590 if gtype ==
'raster':
600 params.append({
'gisprompt' : gisprompt,
602 'description' : values.get(
'description',
''),
603 'guidependency' :
'',
607 'value' : values.get(
'value',
''),
612 'parameterized' :
False,
613 'values_desc' : list(),
621 for action
in self.
GetItems(objType = ModelAction):
622 if not action.IsEnabled():
624 name = action.GetName()
625 params = action.GetParams()
626 for f
in params[
'flags']:
627 if f.get(
'parameterized',
False):
628 if name
not in result:
629 result[name] = {
'flags' : list(),
632 result[name][
'flags'].append(f)
633 for p
in params[
'params']:
634 if p.get(
'parameterized',
False):
635 if name
not in result:
636 result[name] = {
'flags' : list(),
639 result[name][
'params'].append(p)
647 def __init__(self, parent, id = wx.ID_ANY,
648 title = _(
"GRASS GIS Graphical Modeler (experimental prototype)"), **kwargs):
649 """!Graphical modeler main window
651 @param parent parent window
653 @param title window title
655 @param kwargs wx.Frames' arguments
664 "default" : wx.StockCursor(wx.CURSOR_ARROW),
665 "cross" : wx.StockCursor(wx.CURSOR_CROSS),
668 wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
669 self.SetName(
"Modeler")
670 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
682 style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
683 FN.FNB_NO_NAV_BUTTONS | FN.FNB_NO_X_BUTTON)
686 self.canvas.SetBackgroundColour(wx.WHITE)
687 self.canvas.SetCursor(self.
cursors[
"default"])
697 self.notebook.AddPage(page = self.
canvas, text=_(
'Model'), name =
'model')
698 self.notebook.AddPage(page = self.
itemPanel, text=_(
'Items'), name =
'items')
699 self.notebook.AddPage(page = self.
variablePanel, text=_(
'Variables'), name =
'variables')
700 self.notebook.AddPage(page = self.
goutput, text=_(
'Command output'), name =
'output')
701 wx.CallAfter(self.notebook.SetSelectionByName,
'model')
705 self.Bind(wx.EVT_SIZE, self.
OnSize)
708 self.SetMinSize((475, 300))
709 self.SetSize((640, 480))
713 self.goutput.SetSashPosition(int(self.GetSize()[1] * .75))
717 sizer = wx.BoxSizer(wx.VERTICAL)
719 sizer.Add(item = self.
notebook, proportion = 1,
722 self.SetAutoLayout(
True)
728 def _addEvent(self, item):
729 """!Add event to item"""
732 evthandler.SetShape(item)
733 evthandler.SetPreviousHandler(item.GetEventHandler())
734 item.SetEventHandler(evthandler)
745 """!Update window title"""
757 """!Switch to variables page"""
758 self.notebook.SetSelectionByName(
'variables')
766 """!Refresh canvas"""
767 self.SetStatusText(_(
"Redrawing model..."), 0)
769 self.SetStatusText(
"", 0)
774 action = self.
GetModel().GetItems()[event.pid]
775 if hasattr(action,
"task"):
776 action.Update(running =
True)
781 """!Command done (or aborted)"""
783 action = self.
GetModel().GetItems()[event.pid]
784 if hasattr(action,
"task"):
785 action.Update(running =
True)
792 UserSettings.Get(group=
'manager', key=
'askOnQuit', subkey=
'enabled'):
794 message = _(
"Do you want to save changes in the model?")
796 message = _(
"Do you want to store current model settings "
800 dlg = wx.MessageDialog(self,
802 caption=_(
"Quit Graphical Modeler"),
803 style = wx.YES_NO | wx.YES_DEFAULT |
804 wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE)
805 ret = dlg.ShowModal()
808 self.OnWorkspaceSaveAs()
811 elif ret == wx.ID_CANCEL:
819 """Window resized, save to the model"""
824 """!Open preferences dialog"""
829 self.canvas.Refresh()
833 if self.
parent and self.parent.GetName() ==
'LayerManager':
834 log = self.parent.GetLogWindow()
835 log.RunCmd([
'g.manual',
836 'entry=wxGUI.Modeler'])
840 entry =
'wxGUI.Modeler')
843 """!Model properties dialog"""
846 properties = self.model.GetProperties()
848 if dlg.ShowModal() == wx.ID_OK:
850 for key, value
in dlg.GetValues().iteritems():
851 properties[key] = value
852 for action
in self.model.GetItems(objType = ModelAction):
853 action.GetTask().set_flag(
'overwrite', properties[
'overwrite'])
858 """!Delete intermediate data"""
859 rast, vect, rast3d, msg = self.model.GetIntermediateData()
861 if not rast
and not vect
and not rast3d:
862 GMessage(parent = self,
863 message = _(
'Nothing to delete.'))
866 dlg = wx.MessageDialog(parent = self,
867 message= _(
"Do you want to permanently delete data?%s" % msg),
868 caption=_(
"Delete intermediate data?"),
869 style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
871 ret = dlg.ShowModal()
876 self.goutput.RunCmd([
'g.remove',
'rast=%s' %
','.join(rast)])
878 self.goutput.RunCmd([
'g.remove',
'rast3d=%s' %
','.join(rast3d)])
880 self.goutput.RunCmd([
'g.remove',
'vect=%s' %
','.join(vect)])
882 self.SetStatusText(_(
"%d maps deleted from current mapset") % \
883 int(len(rast) + len(rast3d) + len(vect)))
889 """!Create new model"""
890 Debug.msg(4,
"ModelFrame.OnModelNew():")
896 (self.model.GetNumItems() > 0
or len(self.model.GetData()) > 0):
897 dlg = wx.MessageDialog(self, message=_(
"Current model is not empty. "
898 "Do you want to store current settings "
900 caption=_(
"Create new model?"),
901 style=wx.YES_NO | wx.YES_DEFAULT |
902 wx.CANCEL | wx.ICON_QUESTION)
903 ret = dlg.ShowModal()
906 elif ret == wx.ID_CANCEL:
913 self.canvas.GetDiagram().DeleteAllShapes()
915 self.canvas.Refresh()
916 self.itemPanel.Update()
917 self.variablePanel.Reset()
925 """!Load model from file"""
927 dlg = wx.FileDialog(parent = self, message=_(
"Choose model file"),
928 defaultDir = os.getcwd(),
929 wildcard=_(
"GRASS Model File (*.gxm)|*.gxm"))
930 if dlg.ShowModal() == wx.ID_OK:
931 filename = dlg.GetPath()
936 Debug.msg(4,
"ModelFrame.OnModelOpen(): filename=%s" % filename)
945 self.SetStatusText(_(
'%(items)d items (%(actions)d actions) loaded into model') % \
946 {
'items' : self.model.GetNumItems(),
947 'actions' : self.model.GetNumItems(actionOnly =
True) }, 0)
950 """!Save model to file"""
952 dlg = wx.MessageDialog(self, message=_(
"Model file <%s> already exists. "
953 "Do you want to overwrite this file?") % \
955 caption=_(
"Save model"),
956 style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
957 if dlg.ShowModal() == wx.ID_NO:
960 Debug.msg(4,
"ModelFrame.OnModelSave(): filename=%s" % self.
modelFile)
962 self.SetStatusText(_(
'File <%s> saved') % self.
modelFile, 0)
968 """!Create model to file as"""
970 dlg = wx.FileDialog(parent = self,
971 message = _(
"Choose file to save current model"),
972 defaultDir = os.getcwd(),
973 wildcard=_(
"GRASS Model File (*.gxm)|*.gxm"),
977 if dlg.ShowModal() == wx.ID_OK:
978 filename = dlg.GetPath()
984 if filename[-4:] !=
".gxm":
987 if os.path.exists(filename):
988 dlg = wx.MessageDialog(parent = self,
989 message=_(
"Model file <%s> already exists. "
990 "Do you want to overwrite this file?") % filename,
991 caption=_(
"File already exists"),
992 style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
993 if dlg.ShowModal() != wx.ID_YES:
997 Debug.msg(4,
"GMFrame.OnModelSaveAs(): filename=%s" % filename)
1002 self.SetStatusText(_(
'File <%s> saved') % self.
modelFile, 0)
1005 """!Close model file"""
1006 Debug.msg(4,
"ModelFrame.OnModelClose(): file=%s" % self.
modelFile)
1011 (self.model.GetNumItems() > 0
or len(self.model.GetData()) > 0):
1012 dlg = wx.MessageDialog(self, message=_(
"Current model is not empty. "
1013 "Do you want to store current settings "
1015 caption=_(
"Create new model?"),
1016 style=wx.YES_NO | wx.YES_DEFAULT |
1017 wx.CANCEL | wx.ICON_QUESTION)
1018 ret = dlg.ShowModal()
1019 if ret == wx.ID_YES:
1021 elif ret == wx.ID_CANCEL:
1030 self.canvas.GetDiagram().DeleteAllShapes()
1033 self.canvas.Refresh()
1036 """!Run entire model"""
1040 """!Computation finished"""
1041 self.SetStatusText(
'', 0)
1044 """!Validate entire model"""
1045 if self.model.GetNumItems() < 1:
1046 GMessage(parent = self,
1047 message = _(
'Model is empty. Nothing to validate.'))
1051 self.SetStatusText(_(
'Validating model...'), 0)
1052 errList = self.model.Validate()
1053 self.SetStatusText(
'', 0)
1056 GWarning(parent = self,
1057 message = _(
'Model is not valid.\n\n%s') %
'\n'.join(errList))
1059 GMessage(parent = self,
1060 message = _(
'Model is valid.'))
1063 """!Export model to image (default image)
1070 for shape
in self.canvas.GetDiagram().GetShapeList():
1071 w, h = shape.GetBoundingBoxMax()
1086 size = wx.Size(int(xmaxImg - xminImg) + 50,
1087 int(ymaxImg - yminImg) + 50)
1088 bitmap = wx.EmptyBitmap(width = size.width, height = size.height)
1092 dlg = wx.FileDialog(parent = self,
1093 message = _(
"Choose a file name to save the image (no need to add extension)"),
1096 wildcard = filetype,
1097 style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)
1099 if dlg.ShowModal() == wx.ID_OK:
1100 path = dlg.GetPath()
1105 base, ext = os.path.splitext(path)
1106 fileType = ltype[dlg.GetFilterIndex()][
'type']
1107 extType = ltype[dlg.GetFilterIndex()][
'ext']
1109 path = base +
'.' + extType
1111 dc = wx.MemoryDC(bitmap)
1112 dc.SetBackground(wx.WHITE_BRUSH)
1113 dc.SetBackgroundMode(wx.SOLID)
1116 self.canvas.GetDiagram().Clear(dc)
1117 self.canvas.GetDiagram().Redraw(dc)
1120 bitmap.SaveFile(path, fileType)
1121 self.SetStatusText(_(
"Model exported to <%s>") % path)
1126 """!Export model to Python script"""
1128 dlg = wx.FileDialog(parent = self,
1129 message = _(
"Choose file to save"),
1130 defaultDir = os.getcwd(),
1131 wildcard=_(
"Python script (*.py)|*.py"),
1134 if dlg.ShowModal() == wx.ID_OK:
1135 filename = dlg.GetPath()
1141 if filename[-3:] !=
".py":
1144 if os.path.exists(filename):
1145 dlg = wx.MessageDialog(self, message=_(
"File <%s> already exists. "
1146 "Do you want to overwrite this file?") % filename,
1147 caption=_(
"Save file"),
1148 style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
1149 if dlg.ShowModal() == wx.ID_NO:
1155 fd = open(filename,
"w")
1162 os.chmod(filename, stat.S_IRWXU | stat.S_IWUSR)
1164 self.SetStatusText(_(
"Model exported to <%s>") % filename)
1167 """!Define relation between data and action items"""
1168 self.canvas.SetCursor(self.
cursors[
"cross"])
1173 """!Define new loop in the model"""
1176 width, height = self.canvas.GetSize()
1177 loop =
ModelLoop(self, x = width/2, y = height/2,
1178 id = self.model.GetNumItems() + 1)
1179 self.canvas.diagram.AddShape(loop)
1183 self.model.AddItem(loop)
1185 self.canvas.Refresh()
1188 """!Define new condition in the model"""
1191 width, height = self.canvas.GetSize()
1193 id = self.model.GetNumItems() + 1)
1194 self.canvas.diagram.AddShape(cond)
1198 self.model.AddItem(cond)
1200 self.canvas.Refresh()
1203 """!Add action to model"""
1206 self.searchDialog.CentreOnParent()
1208 self.searchDialog.Reset()
1210 if self.searchDialog.ShowModal() == wx.ID_CANCEL:
1211 self.searchDialog.Hide()
1214 cmd = self.searchDialog.GetCmd()
1215 self.searchDialog.Hide()
1220 width, height = self.canvas.GetSize()
1221 if cmd[0] ==
'r.mapcalc':
1222 GMessage(parent = self,
1223 message = _(
"Module r.mapcalc cannot be used in the model. "
1224 "Use r.mapcalculator instead."))
1228 id = self.model.GetNextId())
1229 overwrite = self.model.GetProperties().get(
'overwrite',
None)
1230 if overwrite
is not None:
1231 action.GetTask().set_flag(
'overwrite', overwrite)
1233 self.canvas.diagram.AddShape(action)
1237 self.model.AddItem(action)
1239 self.itemPanel.Update()
1240 self.canvas.Refresh()
1244 win = action.GetPropDialog()
1246 if len(action.GetLog(string =
False)) > 1:
1247 self.
GetOptData(dcmd = action.GetLog(string =
False), layer = action,
1248 params = action.GetParams(), propwin =
None)
1250 menuform.GUI(parent = self, show =
True).ParseCommand(action.GetLog(string =
False),
1251 completed = (self.
GetOptData, action, action.GetParams()))
1252 elif win
and not win.IsShown():
1259 """!Add data item to model
1262 width, height = self.canvas.GetSize()
1263 data =
ModelData(self, x = width/2, y = height/2)
1266 data.SetPropDialog(dlg)
1267 dlg.CentreOnParent()
1268 ret = dlg.ShowModal()
1274 self.canvas.diagram.AddShape(data)
1280 self.model.AddItem(data)
1282 self.canvas.Refresh()
1286 """!Display manual page"""
1287 grass.run_command(
'g.manual',
1288 entry =
'wxGUI.Modeler')
1291 """!Display About window"""
1292 info = wx.AboutDialogInfo()
1294 info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
1295 info.SetName(_(
'wxGUI Graphical Modeler'))
1296 info.SetWebSite(
'http://grass.osgeo.org')
1297 year = grass.version()[
'date']
1298 info.SetDescription(_(
'(C) 2010-%s by the GRASS Development Team\n\n') % year +
1299 '\n'.join(textwrap.wrap(_(
'This program is free software under the GNU General Public License'
1300 '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
1305 """!Process action data"""
1307 width, height = self.canvas.GetSize()
1308 x = [width/2 + 200, width/2 - 200]
1309 for p
in params[
'params']:
1310 if p.get(
'prompt',
'')
in (
'raster',
'vector',
'raster3d')
and \
1311 (p.get(
'value',
None)
or \
1312 (p.get(
'age',
'old') !=
'old' and p.get(
'required',
'no') ==
'yes')):
1313 data = layer.FindData(p.get(
'name',
''))
1315 data.SetValue(p.get(
'value',
''))
1319 data = self.model.FindData(p.get(
'value',
''),
1320 p.get(
'prompt',
''))
1322 if p.get(
'age',
'old') ==
'old':
1324 toShape = layer, param = p.get(
'name',
''))
1327 toShape = data, param = p.get(
'name',
''))
1328 layer.AddRelation(rel)
1329 data.AddRelation(rel)
1334 data =
ModelData(self, value = p.get(
'value',
''),
1335 prompt = p.get(
'prompt',
''),
1336 x = x.pop(), y = height/2)
1338 self.canvas.diagram.AddShape(data)
1341 if p.get(
'age',
'old') ==
'old':
1343 toShape = layer, param = p.get(
'name',
''))
1346 toShape = data, param = p.get(
'name',
''))
1347 layer.AddRelation(rel)
1348 data.AddRelation(rel)
1354 for p
in params[
'params']:
1355 if p.get(
'required',
False)
and \
1356 p.get(
'value',
'') ==
'' and \
1357 p.get(
'default',
'') ==
'':
1360 layer.SetValid(valid)
1363 parameterized =
False
1364 for f
in params[
'flags']:
1365 if f.get(
'parameterized',
False):
1366 parameterized =
True
1368 if not parameterized:
1369 for p
in params[
'params']:
1370 if p.get(
'parameterized',
False):
1371 parameterized =
True
1373 layer.SetParameterized(parameterized)
1375 self.canvas.Refresh()
1378 layer.SetProperties(params, propwin)
1380 self.SetStatusText(layer.GetLog(), 0)
1383 """!Add connection between model objects
1387 fromShape = rel.GetFrom()
1388 toShape = rel.GetTo()
1391 rel.SetPen(wx.BLACK_PEN)
1392 rel.SetBrush(wx.BLACK_BRUSH)
1393 rel.AddArrow(ogl.ARROW_ARROW)
1394 points = rel.GetControlPoints()
1395 rel.MakeLineControlPoints(2)
1398 rel.InsertLineControlPoint(point = wx.RealPoint(x, y))
1402 fromShape.AddLine(rel, toShape)
1406 self.canvas.diagram.AddShape(rel)
1410 """!Load model definition stored in GRASS Model XML file (gxm)
1413 self.model.LoadModel(filename)
1414 except GException, e:
1415 GError(parent = self,
1416 message = _(
"Reading model file <%s> failed.\n"
1417 "Invalid file, unable to parse XML document.") % filename)
1422 self.SetStatusText(_(
"Please wait, loading model..."), 0)
1425 for item
in self.model.GetItems(objType = ModelAction):
1427 self.canvas.diagram.AddShape(item)
1430 for rel
in item.GetRelations():
1431 if rel.GetFrom() == item:
1432 dataItem = rel.GetTo()
1434 dataItem = rel.GetFrom()
1436 self.canvas.diagram.AddShape(dataItem)
1441 for item
in self.model.GetItems(objType = ModelLoop):
1443 self.canvas.diagram.AddShape(item)
1450 for item
in self.model.GetItems(objType = ModelCondition):
1452 self.canvas.diagram.AddShape(item)
1459 self.variablePanel.Update()
1460 self.itemPanel.Update()
1461 self.SetStatusText(
'', 0)
1463 self.canvas.Refresh(
True)
1466 """!Save model to model file, recover original file on error.
1468 @return True on success
1469 @return False on failure
1472 tmpfile = tempfile.TemporaryFile(mode=
'w+b')
1475 except StandardError:
1476 GError(parent = self,
1477 message = _(
"Writing current settings to model file failed."))
1481 mfile = open(filename,
"w")
1483 for line
in tmpfile.readlines():
1486 wx.MessageBox(parent = self,
1487 message = _(
"Unable to open file <%s> for writing.") % filename,
1488 caption = _(
"Error"),
1489 style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
1497 """!Define loop with given list of items"""
1499 items = loop.GetItems()
1504 for rel
in loop.GetRelations():
1505 self.canvas.GetDiagram().RemoveShape(rel)
1509 rel =
ModelRelation(parent = self, fromShape = parent, toShape = item)
1510 dx = item.GetX() - parent.GetX()
1511 dy = item.GetY() - parent.GetY()
1512 loop.AddRelation(rel)
1514 rel.SetControlPoints(((parent.GetX(), parent.GetY() + dy / 2),
1515 (parent.GetX() + dx, parent.GetY() + dy / 2)))
1520 item = loop.GetItems()[-1]
1521 rel =
ModelRelation(parent = self, fromShape = item, toShape = loop)
1522 loop.AddRelation(rel)
1524 dx = (item.GetX() - loop.GetX()) + loop.GetWidth() / 2 + 50
1525 dy = item.GetHeight() / 2 + 50
1526 rel.MakeLineControlPoints(0)
1527 rel.InsertLineControlPoint(point = wx.RealPoint(loop.GetX() - loop.GetWidth() / 2 ,
1529 rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX(),
1530 item.GetY() + item.GetHeight() / 2))
1531 rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX(),
1533 rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - dx,
1535 rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - dx,
1538 self.canvas.Refresh()
1541 """!Define if-else statement with given list of items"""
1543 items = condition.GetItems()
1544 if not items[
'if']
and not items[
'else']:
1548 for rel
in condition.GetRelations():
1549 self.canvas.GetDiagram().RemoveShape(rel)
1551 dxIf = condition.GetX() + condition.GetWidth() / 2
1552 dxElse = condition.GetX() - condition.GetWidth() / 2
1553 dy = condition.GetY()
1554 for branch
in items.keys():
1555 for item
in items[branch]:
1558 condition.AddRelation(rel)
1560 rel.MakeLineControlPoints(0)
1562 rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - item.GetWidth() / 2, item.GetY()))
1563 rel.InsertLineControlPoint(point = wx.RealPoint(dxIf, dy))
1565 rel.InsertLineControlPoint(point = wx.RealPoint(dxElse, dy))
1566 rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - item.GetWidth() / 2, item.GetY()))
1569 self.canvas.Refresh()
1572 """!Canvas where model is drawn"""
1576 ogl.ShapeCanvas.__init__(self, parent)
1580 self.diagram.SetCanvas(self)
1582 self.SetScrollbars(20, 20, 1000/20, 1000/20)
1584 self.Bind(wx.EVT_CHAR, self.
OnChar)
1588 kc = event.GetKeyCode()
1589 diagram = self.GetDiagram()
1590 if kc == wx.WXK_DELETE:
1594 """!Remove selected shapes"""
1595 self.parent.ModelChanged()
1597 diagram = self.GetDiagram()
1598 for shape
in diagram.GetShapeList():
1599 if not shape.Selected():
1601 remList, upList = self.parent.GetModel().RemoveItem(shape)
1603 diagram.RemoveShape(shape)
1605 for item
in remList:
1606 diagram.RemoveShape(item)
1630 """!Record new relation
1632 self.rels.append(rel)
1635 """!Get list of relations
1637 @param fdir True for 'from'
1643 for rel
in self.
rels:
1645 if rel.GetFrom() == self:
1648 if rel.GetTo() == self:
1654 """!Get True if action is enabled, otherwise False"""
1658 """!Enable/disable action"""
1666 """!Add object to the block (loop/condition)
1668 @param item reference to ModelLoop or ModelCondition which
1669 defines loops/condition
1671 if item
not in self.inBlock:
1672 self.inBlock.append(item)
1675 """!Remove object from the block (loop/consition)
1677 @param item reference to ModelLoop or ModelCondition which
1678 defines loops/codition
1681 self.inBlock.remove(item)
1684 """!Get list of related ModelObject(s) which defines block
1687 @return list of ModelObjects
1692 """!Get list of related ids which defines block
1698 ret.append(mo.GetId())
1703 """!Action class (GRASS module)"""
1704 def __init__(self, parent, x, y, id = -1, cmd = None, task = None, width = None, height = None):
1705 ModelObject.__init__(self, id)
1711 width = UserSettings.Get(group=
'modeler', key=
'action', subkey=(
'size',
'width'))
1713 height = UserSettings.Get(group=
'modeler', key=
'action', subkey=(
'size',
'height'))
1730 if self.parent.GetCanvas():
1731 ogl.RectangleShape.__init__(self, width, height)
1733 self.SetCanvas(self.
parent)
1736 self.SetPen(wx.BLACK_PEN)
1741 def _setBrush(self, running = False):
1744 color = UserSettings.Get(group=
'modeler', key=
'action',
1745 subkey=(
'color',
'running'))
1747 color = UserSettings.Get(group=
'modeler', key=
'disabled',
1750 color = UserSettings.Get(group=
'modeler', key=
'action',
1751 subkey=(
'color',
'valid'))
1753 color = UserSettings.Get(group=
'modeler', key=
'action',
1754 subkey=(
'color',
'invalid'))
1756 wxColor = wx.Color(color[0], color[1], color[2])
1757 self.SetBrush(wx.Brush(wxColor))
1762 width = int(UserSettings.Get(group=
'modeler', key=
'action',
1763 subkey=(
'width',
'parameterized')))
1765 width = int(UserSettings.Get(group=
'modeler', key=
'action',
1766 subkey=(
'width',
'default')))
1774 cmd = self.task.getCmd(ignoreErrors =
True)
1775 if cmd
and len(cmd) > 0:
1777 self.AddText(
'(%d) %s' % (self.
id, cmd[0]))
1779 self.AddText(
'(%d) <<%s>>' % (self.
id, _(
"unknown")))
1782 """!Record properties dialog"""
1783 self.task.params = params[
'params']
1784 self.task.flags = params[
'flags']
1788 """!Get properties dialog"""
1792 """!Get logging info"""
1793 cmd = self.task.getCmd(ignoreErrors =
True, ignoreRequired =
True)
1796 variables = self.parent.GetVariables()
1797 fparams = self.parent.GetVariables(params =
True)
1799 for values
in fparams.itervalues():
1800 params = values[
'params']
1803 for variable
in variables:
1804 pattern= re.compile(
'%' + variable)
1808 if variable == p.get(
'name',
''):
1809 value = p.get(
'value',
'')
1812 value = variables[variable].get(
'value',
'')
1814 for idx
in range(len(cmd)):
1815 if pattern.search(cmd[idx]):
1817 cmd[idx] = pattern.sub(value, cmd[idx])
1827 return ' '.join(cmd)
1833 cmd = self.task.getCmd(ignoreErrors =
True)
1834 if cmd
and len(cmd) > 0:
1840 """!Get dictionary of parameters"""
1842 return copy.deepcopy(self.task.get_options())
1844 return self.task.get_options()
1847 """!Get grassTask instance"""
1851 """!Set dictionary of parameters"""
1852 self.task.params = params[
'params']
1853 self.task.flags = params[
'flags']
1856 """!Merge dictionary of parameters"""
1857 if 'flags' in params:
1858 for f
in params[
'flags']:
1859 self.task.set_flag(f[
'name'],
1860 f.get(
'value',
False))
1861 if 'params' in params:
1862 for p
in params[
'params']:
1863 self.task.set_param(p[
'name'],
1867 """!Set instance to be valid/invalid"""
1872 """!Set action parameterized"""
1874 if self.parent.GetCanvas():
1878 """!Check if action is parameterized"""
1882 """!Find data item by name"""
1884 data = rel.GetData()
1885 if name == rel.GetName()
and name
in data.GetName():
1891 """!Update action"""
1899 """!Draw action in canvas"""
1902 ogl.RectangleShape.OnDraw(self, dc)
1905 def __init__(self, parent, x, y, value = '', prompt = '', width = None, height = None):
1908 @param parent window parent
1909 @param x, y position of the shape
1910 @param fname, tname list of parameter names from / to
1912 @param prompt type of GIS element
1913 @param width,height dimension of the shape
1915 ModelObject.__init__(self)
1923 width = UserSettings.Get(group=
'modeler', key=
'data', subkey=(
'size',
'width'))
1925 height = UserSettings.Get(group=
'modeler', key=
'data', subkey=(
'size',
'height'))
1927 if self.parent.GetCanvas():
1928 ogl.EllipseShape.__init__(self, width, height)
1930 self.SetCanvas(self.
parent)
1933 self.SetPen(wx.BLACK_PEN)
1939 """!Checks if data item is intermediate"""
1943 """!Set intermediate flag"""
1950 pen.SetStyle(wx.SHORT_DASH)
1952 pen.SetStyle(wx.SOLID)
1955 ogl.EllipseShape.OnDraw(self, dc)
1958 """!Get logging info"""
1961 name.append(rel.GetName())
1963 return '/'.join(name) +
'=' + self.
value +
' (' + self.
prompt +
')'
1968 """!Get list of names"""
1971 name.append(rel.GetName())
1997 for direction
in (
'from',
'to'):
1999 if direction ==
'from':
2000 action = rel.GetTo()
2002 action = rel.GetFrom()
2004 task =
menuform.GUI(show =
None).ParseCommand(cmd = action.GetLog(string =
False))
2005 task.set_param(rel.GetName(), self.
value)
2006 action.SetParams(params = task.get_options())
2009 """!Get properties dialog"""
2013 """!Get properties dialog"""
2016 def _setBrush(self):
2018 if self.
prompt ==
'raster':
2019 color = UserSettings.Get(group =
'modeler', key =
'data',
2020 subkey = (
'color',
'raster'))
2021 elif self.
prompt ==
'raster3d':
2022 color = UserSettings.Get(group =
'modeler', key =
'data',
2023 subkey = (
'color',
'raster3d'))
2024 elif self.
prompt ==
'vector':
2025 color = UserSettings.Get(group =
'modeler', key =
'data',
2026 subkey = (
'color',
'vector'))
2028 color = UserSettings.Get(group =
'modeler', key =
'action',
2029 subkey = (
'color',
'invalid'))
2030 wxColor = wx.Color(color[0], color[1], color[2])
2031 self.SetBrush(wx.Brush(wxColor))
2035 isParameterized =
False
2037 if rel.GetTo().IsParameterized():
2038 isParameterized =
True
2040 if not isParameterized:
2042 if rel.GetFrom().IsParameterized():
2043 isParameterized =
True
2047 width = int(UserSettings.Get(group =
'modeler', key =
'action',
2048 subkey = (
'width',
'parameterized')))
2050 width = int(UserSettings.Get(group =
'modeler', key =
'action',
2051 subkey = (
'width',
'default')))
2061 name.append(rel.GetName())
2062 self.AddText(
'/'.join(name))
2064 self.AddText(self.
value)
2066 self.AddText(_(
'<not defined>'))
2069 """!Update action"""
2075 """!Data item properties dialog"""
2076 def __init__(self, parent, shape, id = wx.ID_ANY, title = _(
"Data properties"),
2077 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
2082 ElementDialog.__init__(self, parent, title, label = label, etype = etype)
2086 self.element.SetValue(shape.GetValue())
2088 self.Bind(wx.EVT_BUTTON, self.
OnOK, self.btnOK)
2089 self.Bind(wx.EVT_BUTTON, self.
OnCancel, self.btnCancel)
2093 if shape.GetValue():
2097 self.SetMinSize(self.GetSize())
2099 def _getLabel(self):
2101 prompt = self.shape.GetPrompt()
2102 if prompt ==
'raster':
2103 label = _(
'Name of raster map:')
2104 elif prompt ==
'vector':
2105 label = _(
'Name of vector map:')
2108 label = _(
'Name of element:')
2114 self.dataSizer.Add(self.
element, proportion=0,
2115 flag=wx.EXPAND | wx.ALL, border=1)
2117 self.panel.SetSizer(self.sizer)
2118 self.sizer.Fit(self)
2122 self.shape.SetValue(self.GetElement())
2124 elem = self.GetType()
2126 self.shape.SetPrompt(
'raster')
2127 elif elem ==
'vect':
2128 self.shape.SetPrompt(
'raster')
2130 self.parent.canvas.Refresh()
2131 self.parent.SetStatusText(
'', 0)
2132 self.shape.SetPropDialog(
None)
2140 """!Cancel pressed"""
2141 self.shape.SetPropDialog(
None)
2148 """!Model event handler class"""
2150 ogl.ShapeEvtHandler.__init__(self)
2156 """!Left mouse button pressed -> select item & update statusbar"""
2157 shape = self.GetShape()
2158 canvas = shape.GetCanvas()
2159 dc = wx.ClientDC(canvas)
2160 canvas.PrepareDC(dc)
2162 if hasattr(self.
frame,
'defineRelation'):
2163 drel = self.frame.defineRelation
2164 if drel[
'from']
is None:
2165 drel[
'from'] = shape
2166 elif drel[
'to']
is None:
2169 toShape = drel[
'to'])
2173 ret = dlg.ShowModal()
2175 option = dlg.GetOption()
2177 drel[
'from'].AddRelation(rel)
2178 drel[
'to'].AddRelation(rel)
2179 drel[
'from'].Update()
2180 params = {
'params' : [{
'name' : option,
2181 'value' : drel[
'from'].GetValue()}] }
2182 drel[
'to'].MergeParams(params)
2183 self.frame.AddLine(rel)
2186 del self.frame.defineRelation
2188 if shape.Selected():
2189 shape.Select(
False, dc)
2192 shapeList = canvas.GetDiagram().GetShapeList()
2197 toUnselect.append(s)
2199 shape.Select(
True, dc)
2201 for s
in toUnselect:
2204 canvas.Refresh(
False)
2206 if hasattr(shape,
"GetLog"):
2207 self.log.SetStatusText(shape.GetLog(), 0)
2209 self.log.SetStatusText(
'', 0)
2212 """!Left mouse button pressed (double-click) -> show properties"""
2216 """!Show properties dialog"""
2217 self.frame.ModelChanged()
2218 shape = self.GetShape()
2219 if isinstance(shape, ModelAction):
2220 module =
menuform.GUI(parent = self.
frame, show =
True).ParseCommand(shape.GetLog(string =
False),
2221 completed = (self.frame.GetOptData, shape, shape.GetParams()))
2223 elif isinstance(shape, ModelData):
2225 shape.SetPropDialog(dlg)
2226 dlg.CentreOnParent()
2229 elif isinstance(shape, ModelLoop):
2231 dlg.CentreOnParent()
2232 if dlg.ShowModal() == wx.ID_OK:
2233 shape.SetText(dlg.GetCondition())
2235 ids = dlg.GetItems()
2236 for aId
in ids[
'unchecked']:
2237 action = self.frame.GetModel().GetItem(aId)
2238 action.UnSetBlock(shape)
2239 for aId
in ids[
'checked']:
2240 action = self.frame.GetModel().GetItem(aId)
2241 action.SetBlock(shape)
2243 alist.append(action)
2244 shape.SetItems(alist)
2245 self.frame.DefineLoop(shape)
2246 self.frame.GetCanvas().Refresh()
2250 elif isinstance(shape, ModelCondition):
2252 dlg.CentreOnParent()
2253 if dlg.ShowModal() == wx.ID_OK:
2254 shape.SetText(dlg.GetCondition())
2255 ids = dlg.GetItems()
2256 for b
in ids.keys():
2258 for aId
in ids[b][
'unchecked']:
2259 action = self.frame.GetModel().GetItem(aId)
2260 action.UnSetBlock(shape)
2261 for aId
in ids[b][
'checked']:
2262 action = self.frame.GetModel().GetItem(aId)
2263 action.SetBlock(shape)
2265 alist.append(action)
2266 shape.SetItems(alist, branch = b)
2267 self.frame.DefineCondition(shape)
2268 self.frame.GetCanvas().Refresh()
2273 """!Drag shape (begining)"""
2274 self.frame.ModelChanged()
2275 if self._previousHandler:
2276 self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
2279 """!Drag shape (end)"""
2280 if self._previousHandler:
2281 self._previousHandler.OnEndDragLeft(x, y, keys, attachment)
2283 shape = self.GetShape()
2284 if isinstance(shape, ModelLoop):
2285 self.frame.DefineLoop(shape)
2286 elif isinstance(shape, ModelCondition):
2287 self.frame.DefineCondition(shape)
2289 for mo
in shape.GetBlock():
2290 if isinstance(mo, ModelLoop):
2291 self.frame.DefineLoop(mo)
2292 elif isinstance(mo, ModelCondition):
2293 self.frame.DefineCondition(mo)
2297 self.frame.ModelChanged()
2298 if self._previousHandler:
2299 self._previousHandler.OnEndSize(x, y)
2302 """!Right click -> pop-up menu"""
2303 if not hasattr (self,
"popupID"):
2305 for key
in (
'remove',
'enable',
'addPoint',
2306 'delPoint',
'intermediate',
'props',
'id'):
2307 self.
popupID[key] = wx.NewId()
2313 shape = self.GetShape()
2314 popupMenu = wx.Menu()
2315 popupMenu.Append(self.
popupID[
'remove'], text=_(
'Remove'))
2316 self.frame.Bind(wx.EVT_MENU, self.
OnRemove, id = self.
popupID[
'remove'])
2317 if isinstance(shape, ModelAction)
or isinstance(shape, ModelLoop):
2318 if shape.IsEnabled():
2319 popupMenu.Append(self.
popupID[
'enable'], text=_(
'Disable'))
2322 popupMenu.Append(self.
popupID[
'enable'], text=_(
'Enable'))
2323 self.frame.Bind(wx.EVT_MENU, self.
OnEnable, id = self.
popupID[
'enable'])
2325 if isinstance(shape, ModelRelation):
2326 popupMenu.AppendSeparator()
2327 popupMenu.Append(self.
popupID[
'addPoint'], text=_(
'Add control point'))
2329 popupMenu.Append(self.
popupID[
'delPoint'], text=_(
'Remove control point'))
2331 if len(shape.GetLineControlPoints()) == 2:
2332 popupMenu.Enable(self.
popupID[
'delPoint'],
False)
2334 if isinstance(shape, ModelData)
and '@' not in shape.GetValue():
2335 popupMenu.AppendSeparator()
2336 popupMenu.Append(self.
popupID[
'intermediate'], text=_(
'Intermediate'),
2337 kind = wx.ITEM_CHECK)
2338 if self.GetShape().IsIntermediate():
2339 popupMenu.Check(self.
popupID[
'intermediate'],
True)
2343 if isinstance(shape, ModelData)
or \
2344 isinstance(shape, ModelAction)
or \
2345 isinstance(shape, ModelLoop):
2346 popupMenu.AppendSeparator()
2347 popupMenu.Append(self.
popupID[
'props'], text=_(
'Properties'))
2350 if isinstance(shape, ModelAction):
2351 popupMenu.Append(self.
popupID[
'id'], text=_(
'Change ID'))
2354 self.frame.PopupMenu(popupMenu)
2358 """!Change action id"""
2362 """!Disable action"""
2363 self._onEnable(
False)
2366 """!Disable action"""
2369 def _onEnable(self, enable):
2370 shape = self.GetShape()
2371 shape.Enable(enable)
2372 self.frame.ModelChanged()
2373 self.frame.canvas.Refresh()
2376 """!Add control point"""
2377 shape = self.GetShape()
2378 shape.InsertLineControlPoint(point = wx.RealPoint(self.
x, self.
y))
2381 self.frame.ModelChanged()
2382 self.frame.canvas.Refresh()
2385 """!Remove control point"""
2386 shape = self.GetShape()
2387 shape.DeleteLineControlPoint()
2390 self.frame.ModelChanged()
2391 self.frame.canvas.Refresh()
2394 """!Mark data as intermediate"""
2395 self.frame.ModelChanged()
2396 shape = self.GetShape()
2397 shape.SetIntermediate(event.IsChecked())
2398 self.frame.canvas.Refresh()
2403 self.frame.GetCanvas().RemoveSelected()
2404 self.frame.itemPanel.Update()
2407 def __init__(self, parent, id = wx.ID_ANY, title = _(
"Add new GRASS module to the model"),
2408 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
2409 """!Graphical modeler module search window
2411 @param parent parent window
2413 @param title window title
2414 @param kwargs wx.Dialogs' arguments
2418 wx.Dialog.__init__(self, parent = parent, id = id, title = title, **kwargs)
2419 self.SetName(
"ModelerDialog")
2420 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
2422 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
2425 label=
" %s " % _(
"Command"))
2429 wx.CallAfter(self.cmd_prompt.SetFocus)
2432 items = self.cmd_prompt.GetCommandItems()
2436 self.btnOk.SetDefault()
2437 self.btnOk.Enable(
False)
2439 self.cmd_prompt.Bind(wx.EVT_KEY_UP, self.
OnText)
2440 self.search.searchChoice.Bind(wx.EVT_CHOICE, self.
OnText)
2441 self.Bind(wx.EVT_BUTTON, self.
OnOk, self.
btnOk)
2445 self.SetSize((500, 275))
2448 cmdSizer = wx.StaticBoxSizer(self.
cmdBox, wx.VERTICAL)
2449 cmdSizer.Add(item = self.
cmd_prompt, proportion = 1,
2452 btnSizer = wx.StdDialogButtonSizer()
2454 btnSizer.AddButton(self.
btnOk)
2457 mainSizer = wx.BoxSizer(wx.VERTICAL)
2458 mainSizer.Add(item = self.
search, proportion = 0,
2459 flag = wx.EXPAND | wx.ALL, border = 3)
2460 mainSizer.Add(item = cmdSizer, proportion = 1,
2461 flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border = 3)
2462 mainSizer.Add(item = btnSizer, proportion = 0,
2463 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
2465 self.panel.SetSizer(mainSizer)
2466 mainSizer.Fit(self.
panel)
2471 """!Get dialog panel"""
2476 line = self.cmd_prompt.GetCurLine()[0].strip()
2481 cmd = utils.split(str(line))
2482 except UnicodeError:
2483 cmd = utils.split(utils.EncodeString((line)))
2488 """!Button 'OK' pressed"""
2489 self.btnOk.SetFocus()
2493 GError(parent = self,
2494 message = _(
"Command not defined.\n\n"
2495 "Unable to add new action to the model."))
2498 if cmd[0]
not in globalvar.grassCmd[
'all']:
2499 GError(parent = self,
2500 message = _(
"'%s' is not a GRASS module.\n\n"
2501 "Unable to add new action to the model.") % cmd[0])
2504 self.EndModal(wx.ID_OK)
2507 """!Text in prompt changed"""
2508 if self.cmd_prompt.AutoCompActive():
2512 if isinstance(event, wx.KeyEvent):
2513 entry = self.cmd_prompt.GetTextLeft()
2514 elif isinstance(event, wx.stc.StyledTextEvent):
2515 entry = event.GetText()
2517 entry = event.GetString()
2522 self.btnOk.Enable(
False)
2529 self.cmd_prompt.OnCmdErase(
None)
2530 self.btnOk.Enable(
False)
2531 self.cmd_prompt.SetFocus()
2534 """!Data - action relation"""
2535 def __init__(self, parent, fromShape, toShape, param = ''):
2543 if self.parent.GetCanvas():
2544 ogl.LineShape.__init__(self)
2547 if self
in self.fromShape.rels:
2548 self.fromShape.rels.remove(self)
2549 if self
in self.toShape.rels:
2550 self.toShape.rels.remove(self)
2553 """!Get id of 'from' shape"""
2557 """!Get id of 'to' shape"""
2561 """!Get related ModelData instance
2563 @return ModelData instance
2564 @return None if not found
2566 if isinstance(self.
fromShape, ModelData):
2568 elif isinstance(self.
toShape, ModelData):
2574 """!Get parameter name"""
2578 """!Reset related objects"""
2579 self.fromShape.ResetControlPoints()
2580 self.toShape.ResetControlPoints()
2581 self.ResetControlPoints()
2584 """!Set control points"""
2588 """!Get list of control points"""
2595 pen.SetStyle(wx.SOLID)
2599 """!Draw relation"""
2601 ogl.LineShape.OnDraw(self, dc)
2607 """!Relation properties dialog"""
2608 def __init__(self, parent, shape, id = wx.ID_ANY, title = _(
"Relation properties"),
2609 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
2619 wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
2620 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
2622 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
2625 label =
" %s " % _(
"From"))
2627 label =
" %s " % _(
"To"))
2630 style = wx.CB_READONLY,
2632 self.option.Bind(wx.EVT_COMBOBOX, self.
OnOption)
2636 self.btnOk.Enable(
False)
2641 mainSizer = wx.BoxSizer(wx.VERTICAL)
2643 fromSizer = wx.StaticBoxSizer(self.
fromBox, wx.VERTICAL)
2644 self.
_layoutShape(shape = self.shape.GetFrom(), sizer = fromSizer)
2645 toSizer = wx.StaticBoxSizer(self.
toBox, wx.VERTICAL)
2646 self.
_layoutShape(shape = self.shape.GetTo(), sizer = toSizer)
2648 btnSizer = wx.StdDialogButtonSizer()
2650 btnSizer.AddButton(self.
btnOk)
2653 mainSizer.Add(item = fromSizer, proportion = 0,
2654 flag = wx.EXPAND | wx.ALL, border = 5)
2655 mainSizer.Add(item = toSizer, proportion = 0,
2656 flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
2657 mainSizer.Add(item = btnSizer, proportion = 0,
2658 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
2660 self.panel.SetSizer(mainSizer)
2661 mainSizer.Fit(self.
panel)
2664 self.SetSize(self.GetBestSize())
2666 def _layoutShape(self, shape, sizer):
2667 if isinstance(shape, ModelData):
2668 sizer.Add(item = wx.StaticText(parent = self.
panel, id = wx.ID_ANY,
2669 label = _(
"Data: %s") % shape.GetLog()),
2670 proportion = 1, flag = wx.EXPAND | wx.ALL,
2672 elif isinstance(shape, ModelAction):
2673 gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
2674 gridSizer.Add(item = wx.StaticText(parent = self.
panel, id = wx.ID_ANY,
2675 label = _(
"Command:")),
2677 gridSizer.Add(item = wx.StaticText(parent = self.
panel, id = wx.ID_ANY,
2678 label = shape.GetName()),
2680 gridSizer.Add(item = wx.StaticText(parent = self.
panel, id = wx.ID_ANY,
2681 label = _(
"Option:")),
2682 flag = wx.ALIGN_CENTER_VERTICAL,
2684 gridSizer.Add(item = self.
option,
2686 sizer.Add(item = gridSizer,
2687 proportion = 1, flag = wx.EXPAND | wx.ALL,
2690 def _getOptions(self):
2691 """!Get relevant options"""
2693 fromShape = self.shape.GetFrom()
2694 if not isinstance(fromShape, ModelData):
2695 GError(parent = self.
parent,
2696 message = _(
"Relation doesn't start with data item.\n"
2697 "Unable to add relation."))
2700 toShape = self.shape.GetTo()
2701 if not isinstance(toShape, ModelAction):
2702 GError(parent = self.
parent,
2703 message = _(
"Relation doesn't point to GRASS command.\n"
2704 "Unable to add relation."))
2707 prompt = fromShape.GetPrompt()
2708 task = toShape.GetTask()
2709 for p
in task.get_options()[
'params']:
2710 if p.get(
'prompt',
'') == prompt
and \
2712 items.append(p[
'name'])
2715 GError(parent = self.
parent,
2716 message = _(
"No relevant option found.\n"
2717 "Unable to add relation."))
2721 """!Get selected option"""
2722 return self.option.GetStringSelection()
2725 """!Check if relation is valid"""
2730 if event.GetString():
2733 self.btnOk.Enable(
False)
2736 """!Process GRASS model file (gxm)"""
2738 """!A ElementTree handler for the GXM XML file, as defined in
2758 def _filterValue(self, value):
2763 value = value.replace(
'<',
'<')
2764 value = value.replace(
'>',
'>')
2768 def _getNodeText(self, node, tag, default = ''):
2769 """!Get node text"""
2773 return utils.normalize_whitespace(p.text)
2779 def _processWindow(self):
2780 """!Process window properties"""
2781 node = self.root.find(
'window')
2788 def _processProperties(self):
2789 """!Process model properties"""
2790 node = self.root.find(
'properties')
2793 for key
in (
'name',
'description',
'author'):
2796 for f
in node.findall(
'flag'):
2797 name = f.get(
'name',
'')
2798 if name ==
'overwrite':
2801 def _processProperty(self, pnode, name):
2802 """!Process given property"""
2803 node = pnode.find(name)
2804 if node
is not None:
2809 def _processVariables(self):
2810 """!Process model variables"""
2811 vnode = self.root.find(
'variables')
2814 for node
in vnode.findall(
'variable'):
2815 name = node.get(
'name',
'')
2818 self.
variables[name] = {
'type' : node.get(
'type',
'string') }
2819 for key
in (
'description',
'value'):
2822 def _processVariable(self, pnode, name, key):
2823 """!Process given variable"""
2824 node = pnode.find(key)
2825 if node
is not None:
2829 def _processItems(self):
2830 """!Process model items (actions, loops, conditions)"""
2835 def _processActions(self):
2836 """!Process model file"""
2837 for action
in self.root.findall(
'action'):
2838 pos, size = self.
_getDim(action)
2841 task = action.find(
'task')
2842 if task
is not None:
2843 if task.find(
'disabled')
is not None:
2849 aId = int(action.get(
'id', -1))
2851 self.actions.append({
'pos' : pos,
2855 'disabled' : disabled })
2857 def _getDim(self, node):
2858 """!Get position and size of shape"""
2860 posAttr = node.get(
'pos',
None)
2862 posVal =
map(int, posAttr.split(
','))
2864 pos = (posVal[0], posVal[1])
2868 sizeAttr = node.get(
'size',
None)
2870 sizeVal =
map(int, sizeAttr.split(
','))
2872 size = (sizeVal[0], sizeVal[1])
2878 def _processData(self):
2879 """!Process model file"""
2880 for data
in self.root.findall(
'data'):
2881 pos, size = self.
_getDim(data)
2882 param = data.find(
'data-parameter')
2883 prompt = value =
None
2884 if param
is not None:
2885 prompt = param.get(
'prompt',
None)
2888 if data.find(
'intermediate')
is None:
2889 intermediate =
False
2894 for rel
in data.findall(
'relation'):
2895 defrel = {
'id' : int(rel.get(
'id', -1)),
2896 'dir' : rel.get(
'dir',
'to'),
2897 'name' : rel.get(
'name',
'') }
2899 for point
in rel.findall(
'point'):
2902 points.append((float(x), float(y)))
2903 defrel[
'points'] = points
2906 self.data.append({
'pos' : pos,
2910 'intermediate' : intermediate,
2913 def _processTask(self, node):
2916 @return grassTask instance
2917 @return None on error
2920 parameterized = list()
2922 name = node.get(
'name',
None)
2929 for f
in node.findall(
'flag'):
2930 flag = f.get(
'name',
'')
2931 if f.get(
'parameterized',
'0') ==
'1':
2932 parameterized.append((
'flag', flag))
2933 if f.get(
'value',
'1') ==
'0':
2936 cmd.append(
'--' + flag)
2938 cmd.append(
'-' + flag)
2940 for p
in node.findall(
'parameter'):
2941 name = p.get(
'name',
'')
2942 if p.find(
'parameterized')
is not None:
2943 parameterized.append((
'param', name))
2944 cmd.append(
'%s=%s' % (name,
2947 task, err =
menuform.GUI(show =
None, checkError =
True).ParseCommand(cmd = cmd)
2949 GWarning(os.linesep.join(err))
2951 for opt, name
in parameterized:
2953 task.set_flag(name,
True, element =
'parameterized')
2955 task.set_param(name,
True, element =
'parameterized')
2959 def _processLoops(self):
2960 """!Process model loops"""
2961 for node
in self.root.findall(
'loop'):
2962 pos, size = self.
_getDim(node)
2965 for anode
in node.findall(
'item'):
2967 aid.append(int(anode.text))
2971 self.loops.append({
'pos' : pos,
2974 'id' : int(node.get(
'id', -1)),
2977 def _processConditions(self):
2978 """!Process model conditions"""
2979 for node
in self.root.findall(
'if-else'):
2980 pos, size = self.
_getDim(node)
2982 aid = {
'if' : list(),
2984 for b
in aid.keys():
2985 bnode = node.find(b)
2988 for anode
in bnode.findall(
'item'):
2990 aid[b].append(int(anode.text))
2994 self.conditions.append({
'pos' : pos,
2997 'id' : int(node.get(
'id', -1)),
3001 """!Generic class for writing model file"""
3019 for action
in model.GetItems(objType = ModelAction):
3020 for rel
in action.GetRelations():
3021 dataItem = rel.GetData()
3022 if dataItem
not in dataList:
3023 dataList.append(dataItem)
3024 self.
_data(dataList)
3028 def _filterValue(self, value):
3029 """!Make value XML-valid"""
3030 value = value.replace(
'<',
'<')
3031 value = value.replace(
'>',
'>')
3037 self.fd.write(
'<?xml version="1.0" encoding="UTF-8"?>\n')
3038 self.fd.write(
'<!DOCTYPE gxm SYSTEM "grass-gxm.dtd">\n')
3039 self.fd.write(
'%s<gxm>\n' % (
' ' * self.
indent))
3045 self.fd.write(
'%s</gxm>\n' % (
' ' * self.
indent))
3048 """!Write window properties"""
3049 canvas = self.model.GetCanvas()
3053 pos = win.GetPosition()
3054 size = win.GetSize()
3055 self.fd.write(
'%s<window pos="%d,%d" size="%d,%d" />\n' % \
3056 (
' ' * self.
indent, pos[0], pos[1], size[0], size[1]))
3058 def _properties(self):
3059 """!Write model properties"""
3060 self.fd.write(
'%s<properties>\n' % (
' ' * self.
indent))
3063 self.fd.write(
'%s<name>%s</name>\n' % (
' ' * self.
indent, self.
properties[
'name']))
3065 self.fd.write(
'%s<description>%s</description>\n' % (
' ' * self.
indent,
3066 utils.EncodeString(self.
properties[
'description'])))
3068 self.fd.write(
'%s<author>%s</author>\n' % (
' ' * self.
indent,
3069 utils.EncodeString(self.
properties[
'author'])))
3073 self.fd.write(
'%s<flag name="overwrite" />\n' % (
' ' * self.
indent))
3075 self.fd.write(
'%s</properties>\n' % (
' ' * self.
indent))
3077 def _variables(self):
3078 """!Write model variables"""
3081 self.fd.write(
'%s<variables>\n' % (
' ' * self.
indent))
3083 for name, values
in self.variables.iteritems():
3084 self.fd.write(
'%s<variable name="%s" type="%s">\n' % \
3085 (
' ' * self.
indent, name, values[
'type']))
3087 if 'value' in values:
3088 self.fd.write(
'%s<value>%s</value>\n' % \
3089 (
' ' * self.
indent, values[
'value']))
3090 if 'description' in values:
3091 self.fd.write(
'%s<description>%s</description>\n' % \
3092 (
' ' * self.
indent, values[
'description']))
3094 self.fd.write(
'%s</variable>\n' % (
' ' * self.
indent))
3096 self.fd.write(
'%s</variables>\n' % (
' ' * self.
indent))
3099 """!Write actions/loops/conditions"""
3100 for item
in self.
items:
3101 if isinstance(item, ModelAction):
3103 elif isinstance(item, ModelLoop):
3105 elif isinstance(item, ModelCondition):
3108 def _action(self, action):
3109 """!Write actions"""
3110 self.fd.write(
'%s<action id="%d" name="%s" pos="%d,%d" size="%d,%d">\n' % \
3111 (
' ' * self.
indent, action.GetId(), action.GetName(), action.GetX(), action.GetY(),
3112 action.GetWidth(), action.GetHeight()))
3114 self.fd.write(
'%s<task name="%s">\n' % (
' ' * self.
indent, action.GetLog(string =
False)[0]))
3116 if not action.IsEnabled():
3117 self.fd.write(
'%s<disabled />\n' % (
' ' * self.
indent))
3118 for key, val
in action.GetParams().iteritems():
3121 if f.get(
'value',
False)
or f.get(
'parameterized',
False):
3122 if f.get(
'parameterized',
False):
3123 if f.get(
'value',
False) ==
False:
3124 self.fd.write(
'%s<flag name="%s" value="0" parameterized="1" />\n' %
3125 (
' ' * self.
indent, f.get(
'name',
'')))
3127 self.fd.write(
'%s<flag name="%s" parameterized="1" />\n' %
3128 (
' ' * self.
indent, f.get(
'name',
'')))
3130 self.fd.write(
'%s<flag name="%s" />\n' %
3131 (
' ' * self.
indent, f.get(
'name',
'')))
3134 if not p.get(
'value',
''):
3136 self.fd.write(
'%s<parameter name="%s">\n' %
3137 (
' ' * self.
indent, p.get(
'name',
'')))
3139 if p.get(
'parameterized',
False):
3140 self.fd.write(
'%s<parameterized />\n' % (
' ' * self.
indent))
3141 self.fd.write(
'%s<value>%s</value>\n' %
3144 self.fd.write(
'%s</parameter>\n' % (
' ' * self.
indent))
3146 self.fd.write(
'%s</task>\n' % (
' ' * self.
indent))
3148 self.fd.write(
'%s</action>\n' % (
' ' * self.
indent))
3150 def _data(self, dataList):
3152 for data
in dataList:
3153 self.fd.write(
'%s<data pos="%d,%d" size="%d,%d">\n' % \
3154 (
' ' * self.
indent, data.GetX(), data.GetY(),
3155 data.GetWidth(), data.GetHeight()))
3157 self.fd.write(
'%s<data-parameter prompt="%s">\n' % \
3158 (
' ' * self.
indent, data.GetPrompt()))
3160 self.fd.write(
'%s<value>%s</value>\n' %
3163 self.fd.write(
'%s</data-parameter>\n' % (
' ' * self.
indent))
3165 if data.IsIntermediate():
3166 self.fd.write(
'%s<intermediate />\n' % (
' ' * self.
indent))
3169 for ft
in (
'from',
'to'):
3170 for rel
in data.GetRelations(ft):
3172 aid = rel.GetTo().GetId()
3174 aid = rel.GetFrom().GetId()
3175 self.fd.write(
'%s<relation dir="%s" id="%d" name="%s">\n' % \
3176 (
' ' * self.
indent, ft, aid, rel.GetName()))
3178 for point
in rel.GetLineControlPoints()[1:-1]:
3179 self.fd.write(
'%s<point>\n' % (
' ' * self.
indent))
3182 self.fd.write(
'%s<x>%d</x>\n' % (
' ' * self.
indent, int(x)))
3183 self.fd.write(
'%s<y>%d</y>\n' % (
' ' * self.
indent, int(y)))
3185 self.fd.write(
'%s</point>\n' % (
' ' * self.
indent))
3187 self.fd.write(
'%s</relation>\n' % (
' ' * self.
indent))
3190 self.fd.write(
'%s</data>\n' % (
' ' * self.
indent))
3192 def _loop(self, loop):
3194 self.fd.write(
'%s<loop id="%d" pos="%d,%d" size="%d,%d">\n' % \
3195 (
' ' * self.
indent, loop.GetId(), loop.GetX(), loop.GetY(),
3196 loop.GetWidth(), loop.GetHeight()))
3197 text = loop.GetText()
3200 self.fd.write(
'%s<condition>%s</condition>\n' %
3202 for item
in loop.GetItems():
3203 self.fd.write(
'%s<item>%d</item>\n' %
3204 (
' ' * self.
indent, item.GetId()))
3206 self.fd.write(
'%s</loop>\n' % (
' ' * self.
indent))
3208 def _condition(self, condition):
3209 """!Write conditions"""
3210 bbox = condition.GetBoundingBoxMin()
3211 self.fd.write(
'%s<if-else id="%d" pos="%d,%d" size="%d,%d">\n' % \
3212 (
' ' * self.
indent, condition.GetId(), condition.GetX(), condition.GetY(),
3214 text = condition.GetText()
3217 self.fd.write(
'%s<condition>%s</condition>\n' %
3219 items = condition.GetItems()
3220 for b
in items.keys():
3221 if len(items[b]) < 1:
3223 self.fd.write(
'%s<%s>\n' % (
' ' * self.
indent, b))
3225 for item
in items[b]:
3226 self.fd.write(
'%s<item>%d</item>\n' %
3227 (
' ' * self.
indent, item.GetId()))
3229 self.fd.write(
'%s</%s>\n' % (
' ' * self.
indent, b))
3232 self.fd.write(
'%s</if-else>\n' % (
' ' * self.
indent))
3235 """!User preferences dialog"""
3236 def __init__(self, parent, settings = UserSettings,
3237 title = _(
"Modeler settings")):
3239 PreferencesBaseDialog.__init__(self, parent = parent, title = title,
3240 settings = settings)
3248 self.SetMinSize(self.GetBestSize())
3249 self.SetSize(self.size)
3251 def _createGeneralPage(self, notebook):
3252 """!Create notebook page for action settings"""
3253 panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
3254 notebook.AddPage(page = panel, text = _(
"General"))
3257 border = wx.BoxSizer(wx.VERTICAL)
3258 box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
3259 label =
" %s " % _(
"Item properties"))
3260 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
3262 gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
3263 gridSizer.AddGrowableCol(0)
3266 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3267 label = _(
"Disabled:")),
3268 flag = wx.ALIGN_LEFT |
3269 wx.ALIGN_CENTER_VERTICAL,
3271 rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3272 colour = self.settings.Get(group=
'modeler', key=
'disabled', subkey=
'color'),
3273 size = globalvar.DIALOG_COLOR_SIZE)
3274 rColor.SetName(
'GetColour')
3275 self.winId[
'modeler:disabled:color'] = rColor.GetId()
3277 gridSizer.Add(item = rColor,
3278 flag = wx.ALIGN_RIGHT |
3279 wx.ALIGN_CENTER_VERTICAL,
3282 sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
3283 border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
3285 panel.SetSizer(border)
3289 def _createActionPage(self, notebook):
3290 """!Create notebook page for action settings"""
3291 panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
3292 notebook.AddPage(page = panel, text = _(
"Action"))
3295 border = wx.BoxSizer(wx.VERTICAL)
3296 box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
3297 label =
" %s " % _(
"Color"))
3298 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
3300 gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
3301 gridSizer.AddGrowableCol(0)
3304 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3305 label = _(
"Valid:")),
3306 flag = wx.ALIGN_LEFT |
3307 wx.ALIGN_CENTER_VERTICAL,
3309 vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3310 colour = self.settings.Get(group=
'modeler', key=
'action', subkey=(
'color',
'valid')),
3311 size = globalvar.DIALOG_COLOR_SIZE)
3312 vColor.SetName(
'GetColour')
3313 self.winId[
'modeler:action:color:valid'] = vColor.GetId()
3315 gridSizer.Add(item = vColor,
3316 flag = wx.ALIGN_RIGHT |
3317 wx.ALIGN_CENTER_VERTICAL,
3321 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3322 label = _(
"Invalid:")),
3323 flag = wx.ALIGN_LEFT |
3324 wx.ALIGN_CENTER_VERTICAL,
3326 iColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3327 colour = self.settings.Get(group=
'modeler', key=
'action', subkey=(
'color',
'invalid')),
3328 size = globalvar.DIALOG_COLOR_SIZE)
3329 iColor.SetName(
'GetColour')
3330 self.winId[
'modeler:action:color:invalid'] = iColor.GetId()
3332 gridSizer.Add(item = iColor,
3333 flag = wx.ALIGN_RIGHT |
3334 wx.ALIGN_CENTER_VERTICAL,
3338 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3339 label = _(
"Running:")),
3340 flag = wx.ALIGN_LEFT |
3341 wx.ALIGN_CENTER_VERTICAL,
3343 rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3344 colour = self.settings.Get(group=
'modeler', key=
'action', subkey=(
'color',
'running')),
3345 size = globalvar.DIALOG_COLOR_SIZE)
3346 rColor.SetName(
'GetColour')
3347 self.winId[
'modeler:action:color:running'] = rColor.GetId()
3349 gridSizer.Add(item = rColor,
3350 flag = wx.ALIGN_RIGHT |
3351 wx.ALIGN_CENTER_VERTICAL,
3354 sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
3355 border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
3358 box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
3359 label =
" %s " % _(
"Shape size"))
3360 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
3362 gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
3363 gridSizer.AddGrowableCol(0)
3366 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3367 label = _(
"Width:")),
3368 flag = wx.ALIGN_LEFT |
3369 wx.ALIGN_CENTER_VERTICAL,
3372 width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
3374 initial = self.settings.Get(group=
'modeler', key=
'action', subkey=(
'size',
'width')))
3375 width.SetName(
'GetValue')
3376 self.winId[
'modeler:action:size:width'] = width.GetId()
3378 gridSizer.Add(item = width,
3379 flag = wx.ALIGN_RIGHT |
3380 wx.ALIGN_CENTER_VERTICAL,
3384 gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
3385 label=_(
"Height:")),
3386 flag = wx.ALIGN_LEFT |
3387 wx.ALIGN_CENTER_VERTICAL,
3390 height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
3392 initial = self.settings.Get(group=
'modeler', key=
'action', subkey=(
'size',
'height')))
3393 height.SetName(
'GetValue')
3394 self.winId[
'modeler:action:size:height'] = height.GetId()
3396 gridSizer.Add(item = height,
3397 flag = wx.ALIGN_RIGHT |
3398 wx.ALIGN_CENTER_VERTICAL,
3401 sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
3402 border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
3404 panel.SetSizer(border)
3408 def _createDataPage(self, notebook):
3409 """!Create notebook page for data settings"""
3410 panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
3411 notebook.AddPage(page = panel, text = _(
"Data"))
3414 border = wx.BoxSizer(wx.VERTICAL)
3415 box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
3416 label =
" %s " % _(
"Type"))
3417 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
3419 gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
3420 gridSizer.AddGrowableCol(0)
3423 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3424 label = _(
"Raster:")),
3425 flag = wx.ALIGN_LEFT |
3426 wx.ALIGN_CENTER_VERTICAL,
3428 rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3429 colour = self.settings.Get(group=
'modeler', key=
'data', subkey=(
'color',
'raster')),
3430 size = globalvar.DIALOG_COLOR_SIZE)
3431 rColor.SetName(
'GetColour')
3432 self.winId[
'modeler:data:color:raster'] = rColor.GetId()
3434 gridSizer.Add(item = rColor,
3435 flag = wx.ALIGN_RIGHT |
3436 wx.ALIGN_CENTER_VERTICAL,
3440 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3441 label = _(
"3D raster:")),
3442 flag = wx.ALIGN_LEFT |
3443 wx.ALIGN_CENTER_VERTICAL,
3445 r3Color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3446 colour = self.settings.Get(group=
'modeler', key=
'data', subkey=(
'color',
'raster3d')),
3447 size = globalvar.DIALOG_COLOR_SIZE)
3448 r3Color.SetName(
'GetColour')
3449 self.winId[
'modeler:data:color:raster3d'] = r3Color.GetId()
3451 gridSizer.Add(item = r3Color,
3452 flag = wx.ALIGN_RIGHT |
3453 wx.ALIGN_CENTER_VERTICAL,
3457 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3458 label = _(
"Vector:")),
3459 flag = wx.ALIGN_LEFT |
3460 wx.ALIGN_CENTER_VERTICAL,
3462 vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3463 colour = self.settings.Get(group=
'modeler', key=
'data', subkey=(
'color',
'vector')),
3464 size = globalvar.DIALOG_COLOR_SIZE)
3465 vColor.SetName(
'GetColour')
3466 self.winId[
'modeler:data:color:vector'] = vColor.GetId()
3468 gridSizer.Add(item = vColor,
3469 flag = wx.ALIGN_RIGHT |
3470 wx.ALIGN_CENTER_VERTICAL,
3473 sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
3474 border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
3477 box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
3478 label =
" %s " % _(
"Shape size"))
3479 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
3481 gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
3482 gridSizer.AddGrowableCol(0)
3485 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3486 label = _(
"Width:")),
3487 flag = wx.ALIGN_LEFT |
3488 wx.ALIGN_CENTER_VERTICAL,
3491 width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
3493 initial = self.settings.Get(group=
'modeler', key=
'data', subkey=(
'size',
'width')))
3494 width.SetName(
'GetValue')
3495 self.winId[
'modeler:data:size:width'] = width.GetId()
3497 gridSizer.Add(item = width,
3498 flag = wx.ALIGN_RIGHT |
3499 wx.ALIGN_CENTER_VERTICAL,
3503 gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
3504 label=_(
"Height:")),
3505 flag = wx.ALIGN_LEFT |
3506 wx.ALIGN_CENTER_VERTICAL,
3509 height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
3511 initial = self.settings.Get(group=
'modeler', key=
'data', subkey=(
'size',
'height')))
3512 height.SetName(
'GetValue')
3513 self.winId[
'modeler:data:size:height'] = height.GetId()
3515 gridSizer.Add(item = height,
3516 flag = wx.ALIGN_RIGHT |
3517 wx.ALIGN_CENTER_VERTICAL,
3520 sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
3521 border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
3523 panel.SetSizer(border)
3527 def _createLoopPage(self, notebook):
3528 """!Create notebook page for loop settings"""
3529 panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
3530 notebook.AddPage(page = panel, text = _(
"Loop"))
3533 border = wx.BoxSizer(wx.VERTICAL)
3534 box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
3535 label =
" %s " % _(
"Color"))
3536 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
3538 gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
3539 gridSizer.AddGrowableCol(0)
3542 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3543 label = _(
"Valid:")),
3544 flag = wx.ALIGN_LEFT |
3545 wx.ALIGN_CENTER_VERTICAL,
3547 vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
3548 colour = self.settings.Get(group=
'modeler', key=
'loop', subkey=(
'color',
'valid')),
3549 size = globalvar.DIALOG_COLOR_SIZE)
3550 vColor.SetName(
'GetColour')
3551 self.winId[
'modeler:loop:color:valid'] = vColor.GetId()
3553 gridSizer.Add(item = vColor,
3554 flag = wx.ALIGN_RIGHT |
3555 wx.ALIGN_CENTER_VERTICAL,
3558 sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
3559 border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
3562 box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
3563 label =
" %s " % _(
"Shape size"))
3564 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
3566 gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
3567 gridSizer.AddGrowableCol(0)
3570 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
3571 label = _(
"Width:")),
3572 flag = wx.ALIGN_LEFT |
3573 wx.ALIGN_CENTER_VERTICAL,
3576 width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
3578 initial = self.settings.Get(group=
'modeler', key=
'loop', subkey=(
'size',
'width')))
3579 width.SetName(
'GetValue')
3580 self.winId[
'modeler:loop:size:width'] = width.GetId()
3582 gridSizer.Add(item = width,
3583 flag = wx.ALIGN_RIGHT |
3584 wx.ALIGN_CENTER_VERTICAL,
3588 gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
3589 label=_(
"Height:")),
3590 flag = wx.ALIGN_LEFT |
3591 wx.ALIGN_CENTER_VERTICAL,
3594 height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
3596 initial = self.settings.Get(group=
'modeler', key=
'loop', subkey=(
'size',
'height')))
3597 height.SetName(
'GetValue')
3598 self.winId[
'modeler:loop:size:height'] = height.GetId()
3600 gridSizer.Add(item = height,
3601 flag = wx.ALIGN_RIGHT |
3602 wx.ALIGN_CENTER_VERTICAL,
3605 sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
3606 border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
3608 panel.SetSizer(border)
3613 """!Button 'Apply' pressed"""
3614 PreferencesBaseDialog.OnApply(self, event)
3616 self.parent.GetModel().Update()
3617 self.parent.GetCanvas().Refresh()
3620 """!Button 'Save' pressed"""
3621 PreferencesBaseDialog.OnSave(self, event)
3623 self.parent.GetModel().Update()
3624 self.parent.GetCanvas().Refresh()
3627 """!Model properties dialog
3629 def __init__(self, parent, id = wx.ID_ANY,
3630 title = _(
'Model properties'),
3632 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
3633 wx.Dialog.__init__(self, parent, id, title, size = size,
3636 self.
metaBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
3637 label=
" %s " % _(
"Metadata"))
3638 self.
cmdBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
3639 label=
" %s " % _(
"Commands"))
3641 self.
name = wx.TextCtrl(parent = self, id = wx.ID_ANY,
3643 self.
desc = wx.TextCtrl(parent = self, id = wx.ID_ANY,
3644 style = wx.TE_MULTILINE,
3646 self.
author = wx.TextCtrl(parent = self, id = wx.ID_ANY,
3651 label=_(
"Allow output files to overwrite existing files"))
3652 self.overwrite.SetValue(UserSettings.Get(group=
'cmd', key=
'overwrite', subkey=
'enabled'))
3657 self.btnOk.SetDefault()
3659 self.btnOk.SetToolTipString(_(
"Apply properties"))
3660 self.btnOk.SetDefault()
3661 self.btnCancel.SetToolTipString(_(
"Close dialog and ignore changes"))
3668 metaSizer = wx.StaticBoxSizer(self.
metaBox, wx.VERTICAL)
3669 gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
3670 gridSizer.AddGrowableCol(0)
3671 gridSizer.AddGrowableRow(1)
3672 gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
3673 label = _(
"Name:")),
3674 flag = wx.ALIGN_LEFT |
3675 wx.ALIGN_CENTER_VERTICAL,
3677 gridSizer.Add(item = self.
name,
3678 flag = wx.ALIGN_LEFT |
3679 wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
3681 gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
3682 label = _(
"Description:")),
3683 flag = wx.ALIGN_LEFT |
3684 wx.ALIGN_CENTER_VERTICAL,
3686 gridSizer.Add(item = self.
desc,
3687 flag = wx.ALIGN_LEFT |
3688 wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
3690 gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
3691 label = _(
"Author(s):")),
3692 flag = wx.ALIGN_LEFT |
3693 wx.ALIGN_CENTER_VERTICAL,
3695 gridSizer.Add(item = self.
author,
3696 flag = wx.ALIGN_LEFT |
3697 wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
3699 metaSizer.Add(item = gridSizer)
3701 cmdSizer = wx.StaticBoxSizer(self.
cmdBox, wx.VERTICAL)
3703 flag = wx.EXPAND | wx.ALL, border = 3)
3705 btnStdSizer = wx.StdDialogButtonSizer()
3707 btnStdSizer.AddButton(self.
btnOk)
3708 btnStdSizer.Realize()
3710 mainSizer = wx.BoxSizer(wx.VERTICAL)
3711 mainSizer.Add(item=metaSizer, proportion=1,
3712 flag=wx.EXPAND | wx.ALL, border=5)
3713 mainSizer.Add(item=cmdSizer, proportion=0,
3714 flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
3715 mainSizer.Add(item=btnStdSizer, proportion=0,
3716 flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
3718 self.SetSizer(mainSizer)
3726 return {
'name' : self.name.GetValue(),
3727 'description' : self.desc.GetValue(),
3728 'author' : self.author.GetValue(),
3729 'overwrite' : self.overwrite.IsChecked() }
3732 """!Initialize dialog"""
3733 self.name.SetValue(prop[
'name'])
3734 self.desc.SetValue(prop[
'description'])
3735 self.author.SetValue(prop[
'author'])
3736 if 'overwrite' in prop:
3737 self.overwrite.SetValue(prop[
'overwrite'])
3740 def __init__(self, parent, params, id = wx.ID_ANY, title = _(
"Model parameters"),
3741 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
3742 """!Model parameters dialog
3748 wx.Dialog.__init__(self, parent = parent, id = id, title = title, style = style, **kwargs)
3750 if globalvar.hasAgw:
3752 agwStyle = FN.FNB_FANCY_TABS |
3754 FN.FNB_NO_NAV_BUTTONS |
3757 self.
notebook = FN.FlatNotebook(self, id = wx.ID_ANY,
3758 style = FN.FNB_FANCY_TABS |
3760 FN.FNB_NO_NAV_BUTTONS |
3764 wx.CallAfter(self.notebook.SetSelection, 0)
3766 self.
btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
3767 self.
btnRun = wx.Button(parent = self, id = wx.ID_OK,
3769 self.btnRun.SetDefault()
3773 size = self.GetBestSize()
3774 self.SetMinSize(size)
3775 self.SetSize((size.width, size.height +
3776 panel.constrained_size[1] -
3777 panel.panelMinHeight))
3780 btnSizer = wx.StdDialogButtonSizer()
3782 btnSizer.AddButton(self.
btnRun)
3785 mainSizer = wx.BoxSizer(wx.VERTICAL)
3786 mainSizer.Add(item = self.
notebook, proportion = 1,
3788 mainSizer.Add(item=btnSizer, proportion=0,
3789 flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
3791 self.SetSizer(mainSizer)
3794 def _createPages(self):
3795 """!Create for each parameterized module its own page"""
3796 nameOrdered = [
''] * len(self.params.keys())
3797 for name, params
in self.params.iteritems():
3798 nameOrdered[params[
'idx']] = name
3799 for name
in nameOrdered:
3800 params = self.
params[name]
3802 self.notebook.AddPage(panel, text = name)
3806 def _createPage(self, name, params):
3807 """!Define notebook page"""
3808 if name
in globalvar.grassCmd[
'all']:
3809 task = gtask.grassTask(name)
3811 task = gtask.grassTask()
3812 task.flags = params[
'flags']
3813 task.params = params[
'params']
3816 self.tasks.append(task)
3821 """!Check for errors, get list of messages"""
3823 for task
in self.
tasks:
3824 errList += task.getCmdError()
3829 listmix.ListCtrlAutoWidthMixin,
3830 listmix.TextEditMixin,
3831 listmix.ColumnSorterMixin):
3832 def __init__(self, parent, columns, id = wx.ID_ANY,
3833 style = wx.LC_REPORT | wx.BORDER_NONE |
3834 wx.LC_SORT_ASCENDING |wx.LC_HRULES |
3835 wx.LC_VRULES, **kwargs):
3836 """!List of model variables"""
3842 except AttributeError:
3845 wx.ListCtrl.__init__(self, parent, id = id, style = style, **kwargs)
3846 listmix.ListCtrlAutoWidthMixin.__init__(self)
3847 listmix.TextEditMixin.__init__(self)
3848 listmix.ColumnSorterMixin.__init__(self, 4)
3852 self.InsertColumn(i, col)
3853 self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
3859 self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.
OnBeginEdit)
3860 self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.
OnEndEdit)
3861 self.Bind(wx.EVT_LIST_COL_CLICK, self.
OnColClick)
3862 self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp)
3863 self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
3866 """!Editing of item started"""
3870 """!Finish editing of item"""
3874 """!Click on column header (order by)"""
3878 def __init__(self, parent, id = wx.ID_ANY,
3880 """!Manage model variables panel
3884 wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
3886 self.
listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
3887 label=
" %s " % _(
"List of variables - right-click to delete"))
3890 columns = [_(
"Name"), _(
"Data type"),
3891 _(
"Default value"), _(
"Description")])
3894 self.
addBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
3895 label =
" %s " % _(
"Add new variable"))
3896 self.
name = wx.TextCtrl(parent = self, id = wx.ID_ANY)
3897 wx.CallAfter(self.name.SetFocus)
3898 self.
type = wx.Choice(parent = self, id = wx.ID_ANY,
3899 choices = [_(
"integer"),
3904 self.
value = wx.TextCtrl(parent = self, id = wx.ID_ANY)
3905 self.
desc = wx.TextCtrl(parent = self, id = wx.ID_ANY)
3908 self.
btnAdd = wx.Button(parent = self, id = wx.ID_ADD)
3909 self.btnAdd.SetToolTipString(_(
"Add new variable to the model"))
3910 self.btnAdd.Enable(
False)
3913 self.name.Bind(wx.EVT_TEXT, self.
OnText)
3914 self.value.Bind(wx.EVT_TEXT, self.
OnText)
3915 self.desc.Bind(wx.EVT_TEXT, self.
OnText)
3916 self.btnAdd.Bind(wx.EVT_BUTTON, self.
OnAdd)
3921 """!Layout dialog"""
3922 listSizer = wx.StaticBoxSizer(self.
listBox, wx.VERTICAL)
3923 listSizer.Add(item = self.
list, proportion = 1,
3926 addSizer = wx.StaticBoxSizer(self.
addBox, wx.VERTICAL)
3927 gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
3928 gridSizer.AddGrowableCol(1)
3929 gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
3930 label =
"%s:" % _(
"Name")),
3931 flag = wx.ALIGN_CENTER_VERTICAL,
3933 gridSizer.Add(item = self.
name,
3936 gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
3937 label =
"%s:" % _(
"Data type")),
3938 flag = wx.ALIGN_CENTER_VERTICAL,
3940 gridSizer.Add(item = self.
type,
3942 gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
3943 label =
"%s:" % _(
"Default value")),
3944 flag = wx.ALIGN_CENTER_VERTICAL,
3946 gridSizer.Add(item = self.
value,
3947 pos = (1, 1), span = (1, 3),
3949 gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
3950 label =
"%s:" % _(
"Description")),
3951 flag = wx.ALIGN_CENTER_VERTICAL,
3953 gridSizer.Add(item = self.
desc,
3954 pos = (2, 1), span = (1, 3),
3956 addSizer.Add(item = gridSizer,
3958 addSizer.Add(item = self.
btnAdd, proportion = 0,
3959 flag = wx.TOP | wx.ALIGN_RIGHT, border = 5)
3961 mainSizer = wx.BoxSizer(wx.VERTICAL)
3962 mainSizer.Add(item = listSizer, proportion = 1,
3963 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
3964 mainSizer.Add(item = addSizer, proportion = 0,
3965 flag = wx.EXPAND | wx.ALIGN_CENTER |
3966 wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
3968 self.SetSizer(mainSizer)
3973 if self.name.GetValue():
3974 self.btnAdd.Enable()
3976 self.btnAdd.Enable(
False)
3979 """!Add new variable to the list"""
3980 msg = self.list.Append(self.name.GetValue(),
3981 self.type.GetStringSelection(),
3982 self.value.GetValue(),
3983 self.desc.GetValue())
3984 self.name.SetValue(
'')
3985 self.name.SetFocus()
3988 GError(parent = self,
3991 self.type.SetSelection(0)
3992 self.value.SetValue(
'')
3993 self.desc.SetValue(
'')
3997 """!Update model variables"""
3999 for values
in self.list.GetData().itervalues():
4001 variables[name] = {
'type' : str(values[1]) }
4003 variables[name][
'value'] = values[2]
4005 variables[name][
'description'] = values[3]
4007 self.parent.GetModel().SetVariables(variables)
4008 self.parent.ModelChanged()
4011 """!Reload list of variables"""
4012 self.list.OnReload(
None)
4015 """!Remove all variables"""
4016 self.list.DeleteAllItems()
4017 self.parent.GetModel().SetVariables([])
4021 """!List of model variables"""
4022 ModelListCtrl.__init__(self, parent, columns, **kwargs)
4025 """!Used by ColumnSorterMixin"""
4029 """!Get list data"""
4033 """!Populate the list"""
4036 for name, values
in data.iteritems():
4038 values.get(
'value',
''),
4039 values.get(
'description',
'')]
4043 self.DeleteAllItems()
4045 for name, vtype, value, desc
in self.itemDataMap.itervalues():
4046 index = self.InsertStringItem(sys.maxint, name)
4047 self.SetStringItem(index, 0, name)
4048 self.SetStringItem(index, 1, vtype)
4049 self.SetStringItem(index, 2, value)
4050 self.SetStringItem(index, 3, desc)
4051 self.SetItemData(index, i)
4055 """!Append new item to the list
4057 @return None on success
4058 @return error string
4060 for iname, ivtype, ivalue, idesc
in self.itemDataMap.itervalues():
4062 return _(
"Variable <%s> already exists in the model. "
4063 "Adding variable failed.") % name
4065 index = self.InsertStringItem(sys.maxint, name)
4066 self.SetStringItem(index, 0, name)
4067 self.SetStringItem(index, 1, vtype)
4068 self.SetStringItem(index, 2, value)
4069 self.SetStringItem(index, 3, desc)
4078 """!Remove selected variable(s) from the model"""
4079 item = self.GetFirstSelected()
4081 self.DeleteItem(item)
4083 item = self.GetFirstSelected()
4084 self.parent.UpdateModelVariables()
4089 """!Remove all variable(s) from the model"""
4090 dlg = wx.MessageBox(parent=self,
4091 message=_(
"Do you want to delete all variables from "
4093 caption=_(
"Delete variables"),
4094 style=wx.YES_NO | wx.CENTRE)
4098 self.DeleteAllItems()
4101 self.parent.UpdateModelVariables()
4104 """!Finish editing of item"""
4105 itemIndex = event.GetIndex()
4106 columnIndex = event.GetColumn()
4107 nameOld = self.GetItem(itemIndex, 0).GetText()
4109 if columnIndex == 0:
4112 self.
itemDataMap[itemIndex][columnIndex] = event.GetText()
4114 self.parent.UpdateModelVariables()
4117 """!Reload list of variables"""
4118 self.
Populate(self.parent.parent.GetModel().GetVariables())
4121 """!Mouse right button up"""
4122 if not hasattr(self,
"popupID1"):
4132 menu.Append(self.
popupID1, _(
"Delete selected"))
4133 menu.Append(self.
popupID2, _(
"Delete all"))
4134 if self.GetFirstSelected() == -1:
4138 menu.AppendSeparator()
4139 menu.Append(self.
popupID3, _(
"Reload"))
4141 self.PopupMenu(menu)
4145 def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
4146 """!Abstract class for loops and conditions"""
4147 ModelObject.__init__(self, id)
4153 """!Get loop text"""
4157 """!Get items (id)"""
4165 """!Set loop text (condition)"""
4168 self.AddText(
'(' + str(self.
id) +
') ' + self.
text)
4173 return _(
"Condition: ") + self.
text
4175 return _(
"Condition: not defined")
4178 """!Record relation"""
4179 self.rels.append(rel)
4182 """!Clear object, remove rels"""
4186 """!Abstract item properties dialog"""
4187 def __init__(self, parent, shape, title, id = wx.ID_ANY,
4188 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
4192 wx.Dialog.__init__(self, parent, id, title = title, style = style, **kwargs)
4194 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
4197 label=
" %s " % _(
"Condition"))
4199 value = shape.GetText())
4203 columns = [_(
"ID"), _(
"Name"),
4206 self.itemList.Populate(self.parent.GetModel().GetItems())
4210 self.btnOk.SetDefault()
4213 """!Do layout (virtual method)"""
4217 """!Get loop condition"""
4218 return self.condText.GetValue()
4221 def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
4222 """!Defines a loop"""
4223 ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
4226 width = UserSettings.Get(group=
'modeler', key=
'loop', subkey=(
'size',
'width'))
4228 height = UserSettings.Get(group=
'modeler', key=
'loop', subkey=(
'size',
'height'))
4230 if self.parent.GetCanvas():
4231 ogl.RectangleShape.__init__(self, width, height)
4233 self.SetCanvas(self.
parent)
4236 self.SetPen(wx.BLACK_PEN)
4237 self.SetCornerRadius(100)
4239 self.AddText(
'(' + str(self.
id) +
') ' + text)
4241 self.AddText(
'(' + str(self.
id) +
')')
4245 def _setBrush(self):
4248 color = UserSettings.Get(group=
'modeler', key=
'disabled',
4251 color = UserSettings.Get(group=
'modeler', key=
'loop',
4252 subkey=(
'color',
'valid'))
4254 wxColor = wx.Color(color[0], color[1], color[2])
4255 self.SetBrush(wx.Brush(wxColor))
4258 """!Enable/disable action"""
4259 for item
in self.
items:
4260 if not isinstance(item, ModelAction):
4262 item.Enable(enabled)
4264 ModelObject.Enable(self, enabled)
4274 """!Set items (id)"""
4278 """!Loop properties dialog"""
4279 def __init__(self, parent, shape, id = wx.ID_ANY, title = _(
"Loop properties"),
4280 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
4281 ModelItemDialog.__init__(self, parent, shape, title,
4282 style = style, **kwargs)
4285 label=
" %s " % _(
"List of items in loop"))
4288 self.SetMinSize(self.GetSize())
4289 self.SetSize((500, 400))
4293 sizer = wx.BoxSizer(wx.VERTICAL)
4295 condSizer = wx.StaticBoxSizer(self.
condBox, wx.VERTICAL)
4296 condSizer.Add(item = self.
condText, proportion = 1,
4299 listSizer = wx.StaticBoxSizer(self.
listBox, wx.VERTICAL)
4300 listSizer.Add(item = self.
itemList, proportion = 1,
4303 btnSizer = wx.StdDialogButtonSizer()
4305 btnSizer.AddButton(self.
btnOk)
4308 sizer.Add(item = condSizer, proportion = 0,
4309 flag = wx.EXPAND | wx.ALL, border = 3)
4310 sizer.Add(item = listSizer, proportion = 1,
4311 flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
4312 sizer.Add(item = btnSizer, proportion=0,
4313 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
4315 self.panel.SetSizer(sizer)
4316 sizer.Fit(self.
panel)
4321 """!Get list of selected actions"""
4322 return self.itemList.GetItems()
4325 def __init__(self, parent, id = wx.ID_ANY,
4327 """!Manage model items
4331 wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
4333 self.
listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
4334 label=
" %s " % _(
"List of items - right-click to delete"))
4337 columns = [_(
"ID"), _(
"Name"), _(
"In block"),
4338 _(
"Command / Condition")])
4343 """!Layout dialog"""
4344 listSizer = wx.StaticBoxSizer(self.
listBox, wx.VERTICAL)
4345 listSizer.Add(item = self.
list, proportion = 1,
4348 mainSizer = wx.BoxSizer(wx.VERTICAL)
4349 mainSizer.Add(item = listSizer, proportion = 1,
4350 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
4352 self.SetSizer(mainSizer)
4356 """!Reload list of variables"""
4357 self.list.OnReload(
None)
4360 def __init__(self, parent, columns, disablePopup = False, **kwargs):
4361 """!List of model actions"""
4364 ModelListCtrl.__init__(self, parent, columns, **kwargs)
4365 self.SetColumnWidth(1, 100)
4366 self.SetColumnWidth(2, 65)
4369 """!Used by ColumnSorterMixin"""
4373 """!Get list data"""
4377 """!Populate the list"""
4381 if isinstance(self.
shape, ModelCondition):
4382 if self.GetName() ==
'ElseBlockList':
4383 shapeItems =
map(
lambda x: x.GetId(), self.shape.GetItems()[
'else'])
4385 shapeItems =
map(
lambda x: x.GetId(), self.shape.GetItems()[
'if'])
4387 shapeItems =
map(
lambda x: x.GetId(), self.shape.GetItems())
4394 if isinstance(action, ModelData):
4401 aId = action.GetBlockId()
4402 if action.GetId()
in shapeItems:
4405 checked.append(
None)
4407 bId = action.GetBlockId()
4412 ','.join(
map(str, bId)),
4418 self.DeleteAllItems()
4421 for aid, name, desc
in self.itemDataMap.itervalues():
4422 index = self.InsertStringItem(sys.maxint, aid)
4423 self.SetStringItem(index, 0, aid)
4424 self.SetStringItem(index, 1, name)
4425 self.SetStringItem(index, 2, desc)
4426 self.SetItemData(index, i)
4428 self.CheckItem(index,
True)
4431 for aid, name, inloop, desc
in self.itemDataMap.itervalues():
4432 index = self.InsertStringItem(sys.maxint, aid)
4433 self.SetStringItem(index, 0, aid)
4434 self.SetStringItem(index, 1, name)
4435 self.SetStringItem(index, 2, inloop)
4436 self.SetStringItem(index, 3, desc)
4437 self.SetItemData(index, i)
4441 """!Remove selected action(s) from the model"""
4442 model = self.frame.GetModel()
4443 canvas = self.frame.GetCanvas()
4445 item = self.GetFirstSelected()
4447 self.DeleteItem(item)
4450 aId = self.GetItem(item, 0).GetText()
4451 action = model.GetItem(int(aId))
4453 item = self.GetFirstSelected()
4456 model.RemoveItem(action)
4457 canvas.GetDiagram().RemoveShape(action)
4458 self.frame.ModelChanged()
4460 item = self.GetFirstSelected()
4467 """!Remove all variable(s) from the model"""
4468 deleteDialog = wx.MessageBox(parent=self,
4469 message=_(
"Selected data records (%d) will permanently deleted "
4470 "from table. Do you want to delete them?") % \
4471 (len(self.listOfSQLStatements)),
4472 caption=_(
"Delete records"),
4473 style=wx.YES_NO | wx.CENTRE)
4474 if deleteDialog != wx.YES:
4477 self.DeleteAllItems()
4480 self.parent.UpdateModelVariables()
4483 """!Finish editing of item"""
4484 itemIndex = event.GetIndex()
4485 columnIndex = event.GetColumn()
4487 self.
itemDataMap[itemIndex][columnIndex] = event.GetText()
4489 aId = int(self.GetItem(itemIndex, 0).GetText())
4490 action = self.frame.GetModel().GetItem(aId)
4493 if columnIndex == 0:
4494 action.SetId(int(event.GetText()))
4496 self.frame.ModelChanged()
4499 """!Reload list of actions"""
4500 self.
Populate(self.frame.GetModel().GetItems())
4503 """!Mouse right button up"""
4507 if not hasattr(self,
"popupID1"):
4519 menu.Append(self.
popupID1, _(
"Delete selected"))
4520 menu.Append(self.
popupID2, _(
"Delete all"))
4521 if self.GetFirstSelected() == -1:
4525 menu.AppendSeparator()
4526 menu.Append(self.
popupID4, _(
"Normalize"))
4527 menu.Append(self.
popupID3, _(
"Reload"))
4529 self.PopupMenu(menu)
4533 """!Update id of actions"""
4534 model = self.frame.GetModel()
4537 for item
in model.GetItems():
4542 self.frame.GetCanvas().Refresh()
4543 self.frame.ModelChanged()
4546 def __init__(self, parent, shape, columns, window = None, **kwargs):
4550 ItemListCtrl.__init__(self, parent, columns, disablePopup =
True, **kwargs)
4551 listmix.CheckListCtrlMixin.__init__(self)
4552 self.SetColumnWidth(0, 50)
4557 """!Disable editing"""
4561 """!Item checked/unchecked"""
4562 name = self.GetName()
4563 if name ==
'IfBlockList' and self.
window:
4564 self.window.OnCheckItemIf(index, flag)
4565 elif name ==
'ElseBlockList' and self.
window:
4566 self.window.OnCheckItemElse(index, flag)
4569 """!Get list of selected actions"""
4570 ids = {
'checked' : list(),
4571 'unchecked' : list() }
4572 for i
in range(self.GetItemCount()):
4573 iId = int(self.GetItem(i, 0).GetText())
4574 if self.IsChecked(i):
4575 ids[
'checked'].append(iId)
4577 ids[
'unchecked'].append(iId)
4582 """!Check/uncheck given item by id"""
4583 for i
in range(self.GetItemCount()):
4584 iId = int(self.GetItem(i, 0).GetText())
4586 self.CheckItem(i, flag)
4590 def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '',
4591 items = {
'if' : [],
'else' : [] }):
4592 """!Defines a if-else condition"""
4593 ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
4596 self.
width = UserSettings.Get(group=
'modeler', key=
'if-else', subkey=(
'size',
'width'))
4600 self.
height = UserSettings.Get(group=
'modeler', key=
'if-else', subkey=(
'size',
'height'))
4604 if self.parent.GetCanvas():
4605 ogl.PolygonShape.__init__(self)
4607 points = [(0, - self.
height / 2),
4608 (self.
width / 2, 0),
4610 (- self.
width / 2, 0)]
4613 self.SetCanvas(self.
parent)
4616 self.SetPen(wx.BLACK_PEN)
4618 self.AddText(
'(' + str(self.
id) +
') ' + text)
4620 self.AddText(
'(' + str(self.
id) +
')')
4627 """!Get object width"""
4631 """!Get object height"""
4637 @param items list of items
4638 @param branch 'if' / 'else'
4640 if branch
in [
'if',
'else']:
4641 self.
items[branch] = items
4644 """!Condition properties dialog"""
4645 def __init__(self, parent, shape, id = wx.ID_ANY, title = _(
"If-else properties"),
4646 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
4647 ModelItemDialog.__init__(self, parent, shape, title,
4648 style = style, **kwargs)
4651 label=
" %s " % _(
"List of items in 'if' block"))
4653 self.itemListIf.SetName(
'IfBlockList')
4656 label=
" %s " % _(
"List of items in 'else' block"))
4659 columns = [_(
"ID"), _(
"Name"),
4662 self.itemListElse.SetName(
'ElseBlockList')
4663 self.itemListElse.Populate(self.parent.GetModel().
GetItems())
4666 self.SetMinSize(self.GetSize())
4667 self.SetSize((500, 400))
4671 sizer = wx.BoxSizer(wx.VERTICAL)
4673 condSizer = wx.StaticBoxSizer(self.
condBox, wx.VERTICAL)
4674 condSizer.Add(item = self.
condText, proportion = 1,
4677 listIfSizer = wx.StaticBoxSizer(self.
listBoxIf, wx.VERTICAL)
4678 listIfSizer.Add(item = self.
itemListIf, proportion = 1,
4680 listElseSizer = wx.StaticBoxSizer(self.
listBoxElse, wx.VERTICAL)
4681 listElseSizer.Add(item = self.
itemListElse, proportion = 1,
4684 btnSizer = wx.StdDialogButtonSizer()
4686 btnSizer.AddButton(self.
btnOk)
4689 sizer.Add(item = condSizer, proportion = 0,
4690 flag = wx.EXPAND | wx.ALL, border = 3)
4691 sizer.Add(item = listIfSizer, proportion = 1,
4692 flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
4693 sizer.Add(item = listElseSizer, proportion = 1,
4694 flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
4695 sizer.Add(item = btnSizer, proportion=0,
4696 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
4698 self.panel.SetSizer(sizer)
4699 sizer.Fit(self.
panel)
4704 """!Item in if-block checked/unchecked"""
4708 aId = int(self.itemListIf.GetItem(index, 0).GetText())
4709 if aId
in self.itemListElse.GetItems()[
'checked']:
4710 self.itemListElse.CheckItemById(aId,
False)
4713 """!Item in else-block checked/unchecked"""
4717 aId = int(self.itemListElse.GetItem(index, 0).GetText())
4718 if aId
in self.itemListIf.GetItems()[
'checked']:
4719 self.itemListIf.CheckItemById(aId,
False)
4723 return {
'if' : self.itemListIf.GetItems(),
4724 'else' : self.itemListElse.GetItems() }
4728 """!Class for exporting model to Python script
4730 @param fd file desciptor
4738 def _writePython(self):
4739 """!Write model to file"""
4740 properties = self.model.GetProperties()
4743 r"""#!/usr/bin/env python
4745 ############################################################################
4755 #############################################################################
4756 """ % (properties[
'name'],
4757 properties[
'author'],
4758 properties[
'description'],
4767 import grass.script as grass
4771 rast, vect, rast3d, msg = self.model.GetIntermediateData()
4778 r""" grass.run_command('g.remove',
4780 """ %
','.join(
map(
lambda x:
"'" + x +
"'", rast)))
4783 r""" grass.run_command('g.remove',
4785 """ %
','.join(
map(
lambda x:
"'" + x +
"'", vect)))
4788 r""" grass.run_command('g.remove',
4790 """ %
','.join(
map(
lambda x:
"'" + x +
"'", rast3d)))
4791 if not rast
and not vect
and not rast3d:
4792 self.fd.write(
' pass\n')
4794 self.fd.write(
"\ndef main():\n")
4795 for item
in self.model.GetItems():
4798 self.fd.write(
"\n return 0\n")
4802 if __name__ == "__main__":
4803 options, flags = grass.parser()
4804 atexit.register(cleanup)
4808 def _writePythonItem(self, item, ignoreBlock = True):
4809 """!Write model object to Python file"""
4810 if isinstance(item, ModelAction):
4811 if ignoreBlock
and item.GetBlockId():
4814 elif isinstance(item, ModelLoop)
or isinstance(item, ModelCondition):
4816 variables = self.model.GetVariables()
4817 cond = item.GetText()
4818 for variable
in variables:
4819 pattern= re.compile(
'%' + variable)
4820 if pattern.search(cond):
4821 value = variables[variable].get(
'value',
'')
4822 if variables[variable].get(
'type',
'string') ==
'string':
4823 value =
'"' + value +
'"'
4824 cond = pattern.sub(value, cond)
4825 if isinstance(item, ModelLoop):
4826 self.fd.write(
'%sfor %s:\n' % (
' ' * self.
indent, cond))
4828 for action
in item.GetItems():
4832 self.fd.write(
'%sif %s:\n' % (
' ' * self.
indent, cond))
4834 condItems = item.GetItems()
4835 for action
in condItems[
'if']:
4837 if condItems[
'else']:
4839 self.fd.write(
'%selse:\n' % (
' ' * self.
indent))
4841 for action
in condItems[
'else']:
4845 def _writePythonAction(self, item):
4846 """!Write model action to Python file"""
4847 task =
menuform.GUI(show =
None).ParseCommand(cmd = item.GetLog(string =
False))
4848 opts = task.get_options()
4851 strcmd =
"%sgrass.run_command(" % (
' ' * self.
indent)
4852 cmdIndent = len(strcmd)
4853 for f
in opts[
'flags']:
4854 if f.get(
'value',
False) ==
True:
4855 name = f.get(
'name',
'')
4857 params.append(
'%s = True' % name)
4861 for p
in opts[
'params']:
4862 name = p.get(
'name',
None)
4863 value = p.get(
'value',
None)
4865 ptype = p.get(
'type',
'string')
4866 if ptype ==
'string':
4867 params.append(
'%s = "%s"' % (name, value))
4869 params.append(
"%s = %s" % (name, value))
4871 self.fd.write(strcmd +
'"%s"' % task.get_name())
4873 self.fd.write(
",\n%sflags = '%s'" % (
' ' * cmdIndent, flags))
4875 self.fd.write(
",\n")
4876 for opt
in params[:-1]:
4877 self.fd.write(
"%s%s,\n" % (
' ' * cmdIndent, opt))
4878 self.fd.write(
"%s%s)\n" % (
' ' * cmdIndent, params[-1]))
4880 self.fd.write(
")\n")
4884 app = wx.PySimpleApp()
4885 wx.InitAllImageHandlers()
4887 if len(sys.argv) > 1:
4888 frame.LoadModelFile(sys.argv[1])
4893 if __name__ ==
"__main__":