|
@@ -1,7 +1,7 @@
|
|
|
"""!
|
|
|
@package gmodeler.py
|
|
|
|
|
|
-@brief Graphical modeler to create edit, and manage models
|
|
|
+@brief Graphical modeler to create, edit, and manage models
|
|
|
|
|
|
Classes:
|
|
|
- Model
|
|
@@ -45,7 +45,7 @@ import globalvar
|
|
|
if not os.getenv("GRASS_WXBUNDLED"):
|
|
|
globalvar.CheckForWx()
|
|
|
import wx
|
|
|
-import wx.lib.ogl as ogl
|
|
|
+import wx.lib.ogl as ogl
|
|
|
import wx.lib.flatnotebook as FN
|
|
|
import wx.lib.colourselect as csel
|
|
|
|
|
@@ -71,8 +71,8 @@ class Model(object):
|
|
|
self.actions = list() # list of recorded actions
|
|
|
self.data = list() # list of recorded data items
|
|
|
# model properties
|
|
|
- self.properties = { 'name' : '',
|
|
|
- 'description' : '',
|
|
|
+ self.properties = { 'name' : _("model"),
|
|
|
+ 'description' : _("Script generated by wxGUI Graphical Modeler."),
|
|
|
'author' : getpass.getuser() }
|
|
|
|
|
|
self.canvas = canvas
|
|
@@ -186,7 +186,6 @@ class Model(object):
|
|
|
y = data['pos'][1],
|
|
|
width = data['size'][0],
|
|
|
height = data['size'][1],
|
|
|
- name = data['name'],
|
|
|
prompt = data['prompt'],
|
|
|
value = data['value'])
|
|
|
dataItem.SetIntermediate(data['intermediate'])
|
|
@@ -194,14 +193,13 @@ class Model(object):
|
|
|
for rel in data['rels']:
|
|
|
actionItem = self.FindAction(rel['id'])
|
|
|
if rel['dir'] == 'from':
|
|
|
- relation = ModelRelation(dataItem, actionItem)
|
|
|
- relation.SetControlPoints(rel['points'])
|
|
|
- dataItem.AddRelation(relation, direction = 'from')
|
|
|
+ relation = ModelRelation(dataItem, actionItem, rel['name'])
|
|
|
else:
|
|
|
- relation = ModelRelation(actionItem, dataItem)
|
|
|
- relation.SetControlPoints(rel['points'])
|
|
|
- dataItem.AddRelation(relation, direction = 'to')
|
|
|
+ relation = ModelRelation(actionItem, dataItem, rel['name'])
|
|
|
+ relation.SetControlPoints(rel['points'])
|
|
|
+ dataItem.AddRelation(relation, direction = rel['dir'])
|
|
|
|
|
|
+ dataItem.Update()
|
|
|
self.data.append(dataItem)
|
|
|
|
|
|
actionItem.AddData(dataItem)
|
|
@@ -464,12 +462,14 @@ class ModelFrame(wx.Frame):
|
|
|
"""!Model properties dialog"""
|
|
|
dlg = PropertiesDialog(parent = self)
|
|
|
dlg.CentreOnParent()
|
|
|
- dlg.Init(self.model.GetProperties())
|
|
|
+ properties = self.model.GetProperties()
|
|
|
+ dlg.Init(properties)
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
self.ModelChanged()
|
|
|
- self.properties = dlg.GetValues()
|
|
|
+ for key, value in dlg.GetValues().iteritems():
|
|
|
+ properties[key] = value
|
|
|
for action in self.model.GetActions():
|
|
|
- action.GetTask().set_flag('overwrite', self.properties['overwrite'])
|
|
|
+ action.GetTask().set_flag('overwrite', properties['overwrite'])
|
|
|
|
|
|
dlg.Destroy()
|
|
|
|
|
@@ -829,12 +829,7 @@ class ModelFrame(wx.Frame):
|
|
|
|
|
|
def _writePython(self, fd):
|
|
|
"""!Write model to file"""
|
|
|
- if self.properties:
|
|
|
- properties = self.properties
|
|
|
- else:
|
|
|
- properties = { 'name' : _("Graphical modeler script"),
|
|
|
- 'description' : _("Script generated by wxGUI Graphical Modeler"),
|
|
|
- 'author' : getpass.getuser() }
|
|
|
+ properties = self.model.GetProperties()
|
|
|
|
|
|
fd.write(
|
|
|
r"""#!/usr/bin/env python
|
|
@@ -859,15 +854,15 @@ r"""#!/usr/bin/env python
|
|
|
r"""
|
|
|
import sys
|
|
|
import os
|
|
|
-import grass.script as grass
|
|
|
import atexit
|
|
|
+
|
|
|
+import grass.script as grass
|
|
|
""")
|
|
|
|
|
|
# cleanup()
|
|
|
rast, vect, rast3d, msg = self.model.GetIntermediateData()
|
|
|
fd.write(
|
|
|
r"""
|
|
|
-
|
|
|
def cleanup():
|
|
|
""")
|
|
|
if rast:
|
|
@@ -1052,23 +1047,24 @@ if __name__ == "__main__":
|
|
|
data = layer.FindData(p.get('name', ''))
|
|
|
if data:
|
|
|
data.SetValue(p.get('value', ''))
|
|
|
+ data.Update()
|
|
|
continue
|
|
|
|
|
|
data = self.model.FindData(p.get('value', ''),
|
|
|
p.get('prompt', ''))
|
|
|
if data:
|
|
|
if p.get('age', 'old') == 'old':
|
|
|
- rel = ModelRelation(data, layer)
|
|
|
+ rel = ModelRelation(data, layer, p.get('name', ''))
|
|
|
data.AddRelation(rel, direction = 'from')
|
|
|
self.AddLine(rel)
|
|
|
else:
|
|
|
- rel = ModelRelation(layer, data)
|
|
|
+ rel = ModelRelation(layer, data, p.get('name', ''))
|
|
|
data.AddRelation(rel, direction = 'to')
|
|
|
self.AddLine(rel)
|
|
|
+ data.Update()
|
|
|
continue
|
|
|
|
|
|
- data = ModelData(self, name = p.get('name', ''),
|
|
|
- value = p.get('value', ''),
|
|
|
+ data = ModelData(self, value = p.get('value', ''),
|
|
|
prompt = p.get('prompt', ''),
|
|
|
x = x.pop(), y = height/2)
|
|
|
layer.AddData(data)
|
|
@@ -1079,13 +1075,15 @@ if __name__ == "__main__":
|
|
|
self.model.AddData(data)
|
|
|
|
|
|
if p.get('age', 'old') == 'old':
|
|
|
- rel = ModelRelation(data, layer)
|
|
|
+ rel = ModelRelation(data, layer, p.get('name', ''))
|
|
|
data.AddRelation(rel, direction = 'from')
|
|
|
self.AddLine(rel)
|
|
|
else:
|
|
|
- rel = ModelRelation(layer, data)
|
|
|
+ rel = ModelRelation(layer, data, p.get('name', ''))
|
|
|
data.AddRelation(rel, direction = 'to')
|
|
|
self.AddLine(rel)
|
|
|
+ data.Update()
|
|
|
+
|
|
|
# valid ?
|
|
|
valid = True
|
|
|
for p in params['params']:
|
|
@@ -1410,7 +1408,7 @@ class ModelAction(ogl.RectangleShape):
|
|
|
def FindData(self, name):
|
|
|
"""!Find data item by name"""
|
|
|
for d in self.data:
|
|
|
- if d.GetName() == name:
|
|
|
+ if name in d.GetName():
|
|
|
return d
|
|
|
|
|
|
return None
|
|
@@ -1430,10 +1428,17 @@ class ModelAction(ogl.RectangleShape):
|
|
|
ogl.RectangleShape.OnDraw(self, dc)
|
|
|
|
|
|
class ModelData(ogl.EllipseShape):
|
|
|
- """!Data item class"""
|
|
|
- def __init__(self, parent, x, y, name = '', value = '', prompt = '', width = None, height = None):
|
|
|
+ def __init__(self, parent, x, y, value = '', prompt = '', width = None, height = None):
|
|
|
+ """Data item class
|
|
|
+
|
|
|
+ @param parent window parent
|
|
|
+ @param x, y position of the shape
|
|
|
+ @param fname, tname list of parameter names from / to
|
|
|
+ @param value value
|
|
|
+ @param prompt type of GIS element
|
|
|
+ @param width, height dimension of the shape
|
|
|
+ """
|
|
|
self.parent = parent
|
|
|
- self.name = name
|
|
|
self.value = value
|
|
|
self.prompt = prompt
|
|
|
self.intermediate = False
|
|
@@ -1454,16 +1459,8 @@ class ModelData(ogl.EllipseShape):
|
|
|
self.SetPen(wx.BLACK_PEN)
|
|
|
self._setBrush()
|
|
|
|
|
|
- if name:
|
|
|
- self.AddText(name)
|
|
|
- else:
|
|
|
- self.AddText(_('unknown'))
|
|
|
-
|
|
|
- if value:
|
|
|
- self.AddText(value)
|
|
|
- else:
|
|
|
- self.AddText('\n')
|
|
|
-
|
|
|
+ self.AddText(value)
|
|
|
+
|
|
|
def IsIntermediate(self):
|
|
|
"""!Checks if data item is intermediate"""
|
|
|
return self.intermediate
|
|
@@ -1485,15 +1482,20 @@ class ModelData(ogl.EllipseShape):
|
|
|
|
|
|
def GetLog(self, string = True):
|
|
|
"""!Get logging info"""
|
|
|
- if self.name:
|
|
|
- return self.name + '=' + self.value + ' (' + self.prompt + ')'
|
|
|
+ if self.rels['from']:
|
|
|
+ name = self.rels['from'].GetName()
|
|
|
+ return name + '=' + self.value + ' (' + self.prompt + ')'
|
|
|
else:
|
|
|
return _('unknown')
|
|
|
|
|
|
def GetName(self):
|
|
|
- """!Get name"""
|
|
|
- return self.name
|
|
|
-
|
|
|
+ """!Get list of names"""
|
|
|
+ name = list()
|
|
|
+ for rel in self.rels['from'] + self.rels['to']:
|
|
|
+ name.append(rel.GetName())
|
|
|
+
|
|
|
+ return name
|
|
|
+
|
|
|
def GetPrompt(self):
|
|
|
"""!Get prompt"""
|
|
|
return self.prompt
|
|
@@ -1505,12 +1507,7 @@ class ModelData(ogl.EllipseShape):
|
|
|
def SetValue(self, value):
|
|
|
"""!Set value"""
|
|
|
self.value = value
|
|
|
- self.ClearText()
|
|
|
- self.AddText(self.name)
|
|
|
- if value:
|
|
|
- self.AddText(self.value)
|
|
|
- else:
|
|
|
- self.AddText('\n')
|
|
|
+ self._setText()
|
|
|
for direction in ('from', 'to'):
|
|
|
for rel in self.rels[direction]:
|
|
|
if direction == 'from':
|
|
@@ -1520,7 +1517,7 @@ class ModelData(ogl.EllipseShape):
|
|
|
|
|
|
task = menuform.GUI().ParseCommand(cmd = action.GetLog(string = False),
|
|
|
show = None)
|
|
|
- task.set_param(self.name, self.value)
|
|
|
+ task.set_param(rel.GetName(), self.value)
|
|
|
action.SetParams(params = task.get_options())
|
|
|
|
|
|
def GetRelations(self, direction = None):
|
|
@@ -1537,6 +1534,14 @@ class ModelData(ogl.EllipseShape):
|
|
|
"""
|
|
|
self.rels[direction].append(rel)
|
|
|
|
|
|
+ def AddName(self, name, direction):
|
|
|
+ """!Record new name (parameter)
|
|
|
+
|
|
|
+ @param direction direction - 'from' or 'to'
|
|
|
+ """
|
|
|
+ print direction, name
|
|
|
+ self.name[direction].append(name)
|
|
|
+
|
|
|
def GetPropDialog(self):
|
|
|
"""!Get properties dialog"""
|
|
|
return self.propWin
|
|
@@ -1568,11 +1573,21 @@ class ModelData(ogl.EllipseShape):
|
|
|
pen.SetWidth(1)
|
|
|
self.SetPen(pen)
|
|
|
|
|
|
+ def _setText(self):
|
|
|
+ """!Update text"""
|
|
|
+ self.ClearText()
|
|
|
+ name = []
|
|
|
+ for rel in self.rels['to'] + self.rels['from']:
|
|
|
+ name.append(rel.GetName())
|
|
|
+ self.AddText('/'.join(name))
|
|
|
+ self.AddText(self.value)
|
|
|
+
|
|
|
def Update(self):
|
|
|
"""!Update action"""
|
|
|
self._setBrush()
|
|
|
self._setPen()
|
|
|
-
|
|
|
+ self._setText()
|
|
|
+
|
|
|
class ModelDataDialog(ElementDialog):
|
|
|
"""!Data item properties dialog"""
|
|
|
def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Data properties"),
|
|
@@ -1600,6 +1615,9 @@ class ModelDataDialog(ElementDialog):
|
|
|
|
|
|
self.PostInit()
|
|
|
|
|
|
+ if shape.GetValue():
|
|
|
+ self.btnOK.Enable()
|
|
|
+
|
|
|
self._layout()
|
|
|
self.SetMinSize(self.GetSize())
|
|
|
|
|
@@ -1614,6 +1632,7 @@ class ModelDataDialog(ElementDialog):
|
|
|
def OnOK(self, event):
|
|
|
"""!Ok pressed"""
|
|
|
self.shape.SetValue(self.GetElement())
|
|
|
+ self.shape.SetName()
|
|
|
self.parent.canvas.Refresh()
|
|
|
self.parent.SetStatusText('', 0)
|
|
|
self.OnCancel(event)
|
|
@@ -1905,9 +1924,10 @@ class ModelSearchDialog(wx.Dialog):
|
|
|
|
|
|
class ModelRelation(ogl.LineShape):
|
|
|
"""!Data - action relation"""
|
|
|
- def __init__(self, fromShape, toShape):
|
|
|
+ def __init__(self, fromShape, toShape, param = ''):
|
|
|
self.fromShape = fromShape
|
|
|
self.toShape = toShape
|
|
|
+ self.param = param
|
|
|
|
|
|
self._points = None
|
|
|
|
|
@@ -1921,6 +1941,10 @@ class ModelRelation(ogl.LineShape):
|
|
|
"""!Get id of 'to' shape"""
|
|
|
return self.toShape
|
|
|
|
|
|
+ def GetName(self):
|
|
|
+ """!Get parameter name"""
|
|
|
+ return self.param
|
|
|
+
|
|
|
def ResetShapes(self):
|
|
|
"""!Reset related objects"""
|
|
|
self.fromShape.ResetControlPoints()
|
|
@@ -2056,9 +2080,8 @@ class ProcessModelFile:
|
|
|
for data in self.root.findall('data'):
|
|
|
pos, size = self._getDim(data)
|
|
|
param = data.find('data-parameter')
|
|
|
- name = prompt = value = None
|
|
|
+ prompt = value = None
|
|
|
if param is not None:
|
|
|
- name = param.get('name', None)
|
|
|
prompt = param.get('prompt', None)
|
|
|
value = self._filterValue(self._getNodeText(param, 'value'))
|
|
|
|
|
@@ -2070,7 +2093,8 @@ class ProcessModelFile:
|
|
|
rels = list()
|
|
|
for rel in data.findall('relation'):
|
|
|
defrel = { 'id' : int(rel.get('id', -1)),
|
|
|
- 'dir' : rel.get('dir', 'to') }
|
|
|
+ 'dir' : rel.get('dir', 'to'),
|
|
|
+ 'name' : rel.get('name', '') }
|
|
|
points = list()
|
|
|
for point in rel.findall('point'):
|
|
|
x = self._filterValue(self._getNodeText(point, 'x'))
|
|
@@ -2081,7 +2105,6 @@ class ProcessModelFile:
|
|
|
|
|
|
self.data.append({ 'pos' : pos,
|
|
|
'size': size,
|
|
|
- 'name' : name,
|
|
|
'prompt' : prompt,
|
|
|
'value' : value,
|
|
|
'intermediate' : intermediate,
|
|
@@ -2237,8 +2260,8 @@ class WriteModelFile:
|
|
|
(' ' * self.indent, data.GetX(), data.GetY(),
|
|
|
data.GetWidth(), data.GetHeight()))
|
|
|
self.indent += 4
|
|
|
- self.fd.write('%s<data-parameter name="%s" prompt="%s">\n' % \
|
|
|
- (' ' * self.indent, data.GetName(), data.GetPrompt()))
|
|
|
+ self.fd.write('%s<data-parameter prompt="%s">\n' % \
|
|
|
+ (' ' * self.indent, data.GetPrompt()))
|
|
|
self.indent += 4
|
|
|
self.fd.write('%s<value>%s</value>\n' %
|
|
|
(' ' * self.indent, self._filterValue(data.GetValue())))
|
|
@@ -2255,8 +2278,8 @@ class WriteModelFile:
|
|
|
aid = rel.GetTo().GetId()
|
|
|
else:
|
|
|
aid = rel.GetFrom().GetId()
|
|
|
- self.fd.write('%s<relation dir="%s" id="%d">\n' % \
|
|
|
- (' ' * self.indent, ft, aid))
|
|
|
+ self.fd.write('%s<relation dir="%s" id="%d" name="%s">\n' % \
|
|
|
+ (' ' * self.indent, ft, aid, rel.GetName()))
|
|
|
self.indent += 4
|
|
|
for point in rel.GetLineControlPoints()[1:-1]:
|
|
|
self.fd.write('%s<point>\n' % (' ' * self.indent))
|
|
@@ -2656,11 +2679,11 @@ class PropertiesDialog(wx.Dialog):
|
|
|
|
|
|
def GetValues(self):
|
|
|
"""!Get values"""
|
|
|
- return { 'name' : self.name.GetValue(),
|
|
|
- 'description' : self.desc.GetValue(),
|
|
|
- 'author' : self.author.GetValue(),
|
|
|
- 'overwrite' : self.overwrite.IsChecked() }
|
|
|
-
|
|
|
+ return { 'name' : self.name.GetValue(),
|
|
|
+ 'description' : self.desc.GetValue(),
|
|
|
+ 'author' : self.author.GetValue(),
|
|
|
+ 'overwrite' : self.overwrite.IsChecked() }
|
|
|
+
|
|
|
def Init(self, prop):
|
|
|
"""!Initialize dialog"""
|
|
|
self.name.SetValue(prop['name'])
|