Bläddra i källkod

wxGUI/modeler: start implementing loops

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@42545 15284696-431f-4ddb-bdfa-cd5b030d7da7
Martin Landa 15 år sedan
förälder
incheckning
6fc6520e04

+ 115 - 13
gui/wxpython/gui_modules/gmodeler.py

@@ -7,6 +7,7 @@ Classes:
  - Model
  - Model
  - ModelFrame
  - ModelFrame
  - ModelCanvas
  - ModelCanvas
+ - ModelObject
  - ModelAction
  - ModelAction
  - ModelSearchDialog
  - ModelSearchDialog
  - ModelData
  - ModelData
@@ -19,7 +20,8 @@ Classes:
  - ModelParamDialog
  - ModelParamDialog
  - VariablesDialog
  - VariablesDialog
  - ValiablesListCtrl
  - ValiablesListCtrl
-
+ - ModelLoop
+ 
 (C) 2010 by the GRASS Development Team
 (C) 2010 by the GRASS Development Team
 This program is free software under the GNU General Public License
 This program is free software under the GNU General Public License
 (>=v2). Read the file COPYING that comes with GRASS for details.
 (>=v2). Read the file COPYING that comes with GRASS for details.
@@ -74,6 +76,8 @@ class Model(object):
     def __init__(self, canvas = None):
     def __init__(self, canvas = None):
         self.actions    = list()    # list of recorded actions
         self.actions    = list()    # list of recorded actions
         self.data       = list()    # list of recorded data items
         self.data       = list()    # list of recorded data items
+        self.loops      = list()    # list of recorded loops
+        
         # model properties
         # model properties
         self.properties = { 'name'        : _("model"),
         self.properties = { 'name'        : _("model"),
                             'description' : _("Script generated by wxGUI Graphical Modeler."),
                             'description' : _("Script generated by wxGUI Graphical Modeler."),
@@ -91,6 +95,10 @@ class Model(object):
         """!Return list of actions"""
         """!Return list of actions"""
         return self.actions
         return self.actions
     
     
+    def GetLoops(self):
+        """!Return list of loops"""
+        return self.loops
+    
     def GetProperties(self):
     def GetProperties(self):
         """!Get model properties"""
         """!Get model properties"""
         return self.properties
         return self.properties
@@ -222,6 +230,16 @@ class Model(object):
             
             
             actionItem.AddData(dataItem)
             actionItem.AddData(dataItem)
         
         
+        # load loops
+        for loop in gxmXml.loops:
+            loopItem = ModelLoop(parent = self, 
+                                 x = loop['pos'][0],
+                                 y = loop['pos'][1],
+                                 width = loop['size'][0],
+                                 height = loop['size'][1],
+                                 text = loop['text'])
+            self.loops.append(loopItem)
+            
     def IsValid(self):
     def IsValid(self):
         """Return True if model is valid"""
         """Return True if model is valid"""
         if self.Validate():
         if self.Validate():
@@ -996,6 +1014,20 @@ if __name__ == "__main__":
         self.defineRelation = { 'from' : None,
         self.defineRelation = { 'from' : None,
                                 'to'   : None }
                                 'to'   : None }
         
         
+    def OnDefineLoop(self, event):
+        """!Define new loop in the model"""
+        self.ModelChanged()
+
+        width, height = self.canvas.GetSize()
+        loop = ModelLoop(self, x = width/2, y = height/2)
+        self.canvas.diagram.AddShape(loop)
+        loop.Show(True)
+
+        self._addEvent(loop)
+        # self.model.AddAction(action)
+        
+        self.canvas.Refresh()
+
     def OnAddAction(self, event):
     def OnAddAction(self, event):
         """!Add action to model"""
         """!Add action to model"""
         if self.searchDialog is None:
         if self.searchDialog is None:
@@ -1224,6 +1256,12 @@ if __name__ == "__main__":
             for rel in data.GetRelations():
             for rel in data.GetRelations():
                 self.AddLine(rel)
                 self.AddLine(rel)
         
         
+        # load loops
+        for loop in self.model.GetLoops():
+            self._addEvent(loop)
+            self.canvas.diagram.AddShape(loop)
+            loop.Show(True)
+        
         self.SetStatusText('', 0)
         self.SetStatusText('', 0)
         
         
         self.canvas.Refresh(True)
         self.canvas.Refresh(True)
@@ -1237,11 +1275,7 @@ if __name__ == "__main__":
         self.ModelChanged(False)
         self.ModelChanged(False)
         tmpfile = tempfile.TemporaryFile(mode='w+b')
         tmpfile = tempfile.TemporaryFile(mode='w+b')
         try:
         try:
-            WriteModelFile(fd = tmpfile,
-                           actions = self.model.GetActions(),
-                           data = self.model.GetData(),
-                           properties = self.model.GetProperties(),
-                           variables = self.model.GetVariables())
+            WriteModelFile(fd = tmpfile, model = self.model)
         except StandardError:
         except StandardError:
             GMessage(parent = self,
             GMessage(parent = self,
                      message = _("Writing current settings to model file failed."))
                      message = _("Writing current settings to model file failed."))
@@ -1803,6 +1837,12 @@ class ModelEvtHandler(ogl.ShapeEvtHandler):
         self.frame.ModelChanged()
         self.frame.ModelChanged()
         if self._previousHandler:
         if self._previousHandler:
             self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
             self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
+
+    def OnEndSize(self, x, y):
+        """!Resize shape"""
+        self.frame.ModelChanged()
+        if self._previousHandler:
+            self._previousHandler.OnEndSize(x, y)
         
         
     def OnRightClick(self, x, y, keys = 0, attachment = 0):
     def OnRightClick(self, x, y, keys = 0, attachment = 0):
         """!Right click -> pop-up menu"""
         """!Right click -> pop-up menu"""
@@ -2077,11 +2117,13 @@ class ProcessModelFile:
         self.variables  = dict() 
         self.variables  = dict() 
         self.actions = list()
         self.actions = list()
         self.data    = list()
         self.data    = list()
+        self.loops   = list()
         
         
         self._processProperties()
         self._processProperties()
         self._processVariables()
         self._processVariables()
         self._processActions()
         self._processActions()
         self._processData()
         self._processData()
+        self._processLoops()
         
         
     def _filterValue(self, value):
     def _filterValue(self, value):
         """!Filter value
         """!Filter value
@@ -2127,7 +2169,10 @@ class ProcessModelFile:
 
 
     def _processVariables(self):
     def _processVariables(self):
         """!Process model variables"""
         """!Process model variables"""
-        for node in self.root.findall('variable'):
+        vnode = self.root.find('variables')
+        if vnode is None:
+            return
+        for node in vnode.findall('variable'):
             name = node.get('name', '')
             name = node.get('name', '')
             if not name:
             if not name:
                 continue # should not happen
                 continue # should not happen
@@ -2264,15 +2309,26 @@ class ProcessModelFile:
                 task.set_param(name, True, element = 'parameterized')
                 task.set_param(name, True, element = 'parameterized')
         
         
         return task
         return task
-    
+
+    def _processLoops(self):
+        """!Process model loops"""
+        for node in self.root.findall('loop'):
+            pos, size = self._getDim(node)
+            text = self._filterValue(self._getNodeText(node, 'value')).strip()
+            
+            self.loops.append({ 'pos' : pos,
+                                'size': size,
+                                'text' : text })
+        
 class WriteModelFile:
 class WriteModelFile:
     """!Generic class for writing model file"""
     """!Generic class for writing model file"""
-    def __init__(self, fd, actions, data, properties, variables):
+    def __init__(self, fd, model):
         self.fd         = fd
         self.fd         = fd
-        self.actions    = actions
-        self.data       = data
-        self.properties = properties
-        self.variables  = variables
+        self.actions    = model.GetActions()
+        self.data       = model.GetData()
+        self.properties = model.GetProperties()
+        self.variables  = model.GetVariables()
+        self.loops      = model.GetLoops()
         
         
         self.indent = 0
         self.indent = 0
         
         
@@ -2282,6 +2338,7 @@ class WriteModelFile:
         self._variables()
         self._variables()
         self._actions()
         self._actions()
         self._data()
         self._data()
+        self._loops()
         
         
         self._footer()
         self._footer()
 
 
@@ -2322,6 +2379,8 @@ class WriteModelFile:
 
 
     def _variables(self):
     def _variables(self):
         """!Write model variables"""
         """!Write model variables"""
+        self.fd.write('%s<variables>\n' % (' ' * self.indent))
+        self.indent += 4
         for name, values in self.variables.iteritems():
         for name, values in self.variables.iteritems():
             self.fd.write('%s<variable name="%s" type="%s">\n' % \
             self.fd.write('%s<variable name="%s" type="%s">\n' % \
                               (' ' * self.indent, name, values['type']))
                               (' ' * self.indent, name, values['type']))
@@ -2334,6 +2393,8 @@ class WriteModelFile:
                                   (' ' * self.indent, values['description']))
                                   (' ' * self.indent, values['description']))
             self.indent -= 4
             self.indent -= 4
             self.fd.write('%s</variable>\n' % (' ' * self.indent))
             self.fd.write('%s</variable>\n' % (' ' * self.indent))
+        self.indent -= 4
+        self.fd.write('%s</variables>\n' % (' ' * self.indent))
         
         
     def _actions(self):
     def _actions(self):
         """!Write actions"""
         """!Write actions"""
@@ -2425,6 +2486,21 @@ class WriteModelFile:
                 
                 
             self.indent -= 4
             self.indent -= 4
             self.fd.write('%s</data>\n' % (' ' * self.indent))
             self.fd.write('%s</data>\n' % (' ' * self.indent))
+
+    def _loops(self):
+        """!Write loops"""
+        for loop in self.loops:
+            self.fd.write('%s<loop pos="%d,%d" size="%d,%d">\n' % \
+                              (' ' * self.indent, loop.GetX(), loop.GetY(),
+                               loop.GetWidth(), loop.GetHeight()))
+            text = loop.GetText()
+            if text:
+                self.indent += 4
+                self.fd.write('%s<value>%s</value>\n' %
+                              (' ' * self.indent, self._filterValue(text)))
+                self.indent -= 4
+
+            self.fd.write('%s</loop>\n' % (' ' * self.indent))
             
             
 class PreferencesDialog(PreferencesBaseDialog):
 class PreferencesDialog(PreferencesBaseDialog):
     """!User preferences dialog"""
     """!User preferences dialog"""
@@ -3189,7 +3265,33 @@ class VariablesListCtrl(wx.ListCtrl,
     def OnColClick(self, event):
     def OnColClick(self, event):
         """!Click on column header (order by)"""
         """!Click on column header (order by)"""
         event.Skip()
         event.Skip()
+
+class ModelLoop(ogl.RectangleShape):
+    def __init__(self, parent, x, y, width = None, height = None, text = None):
+        """!Defines a loop"""
+        self.parent  = parent
+        self.text    = text
+        if not width:
+            width = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'width'))
+        if not height:
+            height = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'height'))
         
         
+        if self.parent.GetCanvas():
+            ogl.RectangleShape.__init__(self, width, height)
+            
+            self.SetCanvas(self.parent)
+            self.SetX(x)
+            self.SetY(y)
+            self.SetPen(wx.BLACK_PEN)
+            self.SetCornerRadius(100)
+            
+            if text:
+                self.AddText(text)
+
+    def GetText(self):
+        """!Get loop text"""
+        return self.text
+    
 def main():
 def main():
     app = wx.PySimpleApp()
     app = wx.PySimpleApp()
     wx.InitAllImageHandlers()
     wx.InitAllImageHandlers()

+ 6 - 0
gui/wxpython/gui_modules/preferences.py

@@ -552,6 +552,12 @@ class Settings:
                         'height' : 50,
                         'height' : 50,
                         },
                         },
                     },
                     },
+                'loop' : {
+                    'size' : {
+                        'width' : 175,
+                        'height' : 50,
+                        },
+                    },
                 },
                 },
             }
             }
         
         

+ 2 - 1
gui/wxpython/xml/grass-gxm.dtd

@@ -14,7 +14,7 @@
 
 
 <!ELEMENT grass-gxm (gxm)>
 <!ELEMENT grass-gxm (gxm)>
 
 
-<!ELEMENT gxm (action*, data*, properties?, variable*)>
+<!ELEMENT gxm (action*, data*, properties?, variables?)>
 
 
 <!--    an action defines action properties (usually GRASS modules)
 <!--    an action defines action properties (usually GRASS modules)
 -->
 -->
@@ -90,6 +90,7 @@
 
 
 <!--	a variable describes model variable
 <!--	a variable describes model variable
 -->
 -->
+<!ELEMENT variables       (variable*)>
 <!ELEMENT variable        (description?, value?)>
 <!ELEMENT variable        (description?, value?)>
 <!ATTLIST variable  name  CDATA                      #REQUIRED>
 <!ATTLIST variable  name  CDATA                      #REQUIRED>
 <!ATTLIST variable  type  (integer | float | string) #REQUIRED>
 <!ATTLIST variable  type  (integer | float | string) #REQUIRED>

+ 6 - 0
gui/wxpython/xml/menudata_modeler.xml

@@ -82,6 +82,12 @@
 	  <handler>OnDefineRelation</handler>
 	  <handler>OnDefineRelation</handler>
 	</menuitem>
 	</menuitem>
 	<menuitem>
 	<menuitem>
+	  <label>Define loop</label>
+	  <help>Defines loop in the model</help>
+	  <handler>OnDefineLoop</handler>
+	  <shortcut>Ctrl+L</shortcut>
+	</menuitem>
+	<menuitem>
 	  <label>Remove item</label>
 	  <label>Remove item</label>
 	  <help>Remove action/data from model</help>
 	  <help>Remove action/data from model</help>
 	  <handler>OnRemoveItem</handler>
 	  <handler>OnRemoveItem</handler>