Преглед на файлове

wxGUI/modeler: dialog for managing variables implemented

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@42528 15284696-431f-4ddb-bdfa-cd5b030d7da7
Martin Landa преди 15 години
родител
ревизия
653dd665ec
променени са 3 файла, в които са добавени 302 реда и са изтрити 7 реда
  1. 288 6
      gui/wxpython/gui_modules/gmodeler.py
  2. 1 0
      gui/wxpython/gui_modules/vdigit.py
  3. 13 1
      gui/wxpython/xml/grass-gxm.dtd

+ 288 - 6
gui/wxpython/gui_modules/gmodeler.py

@@ -17,6 +17,8 @@ Classes:
  - PreferencesDialog
  - PreferencesDialog
  - PropertiesDialog
  - PropertiesDialog
  - ModelParamDialog
  - ModelParamDialog
+ - VariablesDialog
+ - ValiablesListCtrl
 
 
 (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
@@ -45,9 +47,10 @@ import globalvar
 if not os.getenv("GRASS_WXBUNDLED"):
 if not os.getenv("GRASS_WXBUNDLED"):
     globalvar.CheckForWx()
     globalvar.CheckForWx()
 import wx
 import wx
-import wx.lib.ogl          as ogl
-import wx.lib.flatnotebook as FN
-import wx.lib.colourselect as csel
+import wx.lib.ogl             as ogl
+import wx.lib.flatnotebook    as FN
+import wx.lib.colourselect    as csel
+import wx.lib.mixins.listctrl as listmix
 
 
 import menu
 import menu
 import menudata
 import menudata
@@ -74,6 +77,8 @@ class Model(object):
         self.properties = { 'name'        : _("model"),
         self.properties = { 'name'        : _("model"),
                             'description' : _("Script generated by wxGUI Graphical Modeler."),
                             'description' : _("Script generated by wxGUI Graphical Modeler."),
                             'author'      : getpass.getuser() }
                             'author'      : getpass.getuser() }
+        # model variables
+        self.variables = dict()
         
         
         self.canvas  = canvas
         self.canvas  = canvas
         
         
@@ -88,6 +93,14 @@ class Model(object):
     def GetProperties(self):
     def GetProperties(self):
         """!Get model properties"""
         """!Get model properties"""
         return self.properties
         return self.properties
+
+    def GetVariables(self):
+        """!Get model variables"""
+        return self.variables
+    
+    def SetVariables(self, data):
+        """!Set model variables"""
+        self.variables = data
     
     
     def GetData(self):
     def GetData(self):
         """!Return list of data"""
         """!Return list of data"""
@@ -476,8 +489,10 @@ class ModelFrame(wx.Frame):
         
         
     def OnModelVariables(self, event):
     def OnModelVariables(self, event):
         """!Manage (define) model variables"""
         """!Manage (define) model variables"""
-        pass
-    
+        dlg = VariablesDialog(parent = self, data = self.model.GetVariables())
+        dlg.CentreOnParent()
+        dlg.Show()
+        
     def OnDeleteData(self, event):
     def OnDeleteData(self, event):
         """!Delete intermediate data"""
         """!Delete intermediate data"""
         rast, vect, rast3d, msg = self.model.GetIntermediateData()
         rast, vect, rast3d, msg = self.model.GetIntermediateData()
@@ -2015,6 +2030,7 @@ class ProcessModelFile:
         self.data    = list()
         self.data    = list()
         
         
         self._processProperties()
         self._processProperties()
+        self._processVariables()
         self._processActions()
         self._processActions()
         self._processData()
         self._processData()
         
         
@@ -2060,7 +2076,11 @@ class ProcessModelFile:
             self.properties[name] = node.text
             self.properties[name] = node.text
         else:
         else:
             self.properties[name] = ''
             self.properties[name] = ''
-            
+
+    def _processVariables(self):
+        for node in self.root.findall('variable'):
+            pass
+        
     def _processActions(self):
     def _processActions(self):
         """!Process model file"""
         """!Process model file"""
         for action in self.root.findall('action'):
         for action in self.root.findall('action'):
@@ -2788,6 +2808,268 @@ class ModelParamDialog(wx.Dialog):
         panel = menuform.cmdPanel(parent = self, id = wx.ID_ANY, task = task)
         panel = menuform.cmdPanel(parent = self, id = wx.ID_ANY, task = task)
         
         
         return panel
         return panel
+
+class VariablesDialog(wx.Dialog, listmix.ColumnSorterMixin):
+    def __init__(self, parent, id = wx.ID_ANY, title = _("Manage model variables"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+                 data = dict(), **kwargs):
+        """!Manage model variables dialog
+    
+        @param parent
+        @param title dialog title
+        @param style
+        """
+        self.parent = parent
+        
+        wx.Dialog.__init__(self, parent = parent, id = id, title = title,
+                           style = style, **kwargs)
+        
+        self.listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                    label=" %s " % _("List of variables - right-click to delete"))
+
+        self.list = VariablesListCtrl(parent = self, id = wx.ID_ANY,
+                                      style = wx.LC_REPORT | wx.BORDER_NONE |
+                                      wx.LC_SORT_ASCENDING |wx.LC_HRULES |
+                                      wx.LC_VRULES)
+        if data:
+            self.list.Populate(data)
+        
+        # sorter
+        listmix.ColumnSorterMixin.__init__(self, 2)
+
+        # add new category
+        self.addBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                   label = " %s " % _("Add new variable"))
+        self.name = wx.TextCtrl(parent = self, id = wx.ID_ANY, size = (150, -1))
+        wx.CallAfter(self.name.SetFocus)
+        self.type = wx.Choice(parent = self, id = wx.ID_ANY,
+                              choices = [_("integer"),
+                                         _("float"),
+                                         _("string")])
+        self.value = wx.TextCtrl(parent = self, id = wx.ID_ANY, size = (150, -1))
+        self.desc = wx.TextCtrl(parent = self, id = wx.ID_ANY, size = (350, -1))
+        
+        # buttons
+        self.btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
+        self.btnCancel.SetToolTipString(_("Ignore changes and close dialog"))
+        self.btnOk = wx.Button(parent = self, id = wx.ID_OK)
+        self.btnOk.SetToolTipString(_("Apply changes and close dialog"))
+        self.btnOk.SetDefault()
+        self.btnAdd = wx.Button(parent = self, id = wx.ID_ADD)
+        self.btnAdd.SetToolTipString(_("Add new variable to the model"))
+        self.btnAdd.Enable(False)
+        
+        # bindings
+        self.btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
+        self.name.Bind(wx.EVT_TEXT, self.OnText)
+        self.value.Bind(wx.EVT_TEXT, self.OnText)
+        self.desc.Bind(wx.EVT_TEXT, self.OnText)
+        self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAdd)
+        
+        # list
+        self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
+        self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK
+        # self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list)
+        # self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list)
+        # self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
+        
+        self._layout()
+
+    def _layout(self):
+        """!Layout dialog"""
+        listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
+        listSizer.Add(item = self.list, proportion = 1,
+                      flag = wx.EXPAND)
+        
+        addSizer = wx.StaticBoxSizer(self.addBox, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridSizer.AddGrowableCol(3)
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Name")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 0))
+        gridSizer.Add(item = self.name,
+                      pos = (0, 1))
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Data type")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 2))
+        gridSizer.Add(item = self.type,
+                      pos = (0, 3))
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Default value")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (1, 0))
+        gridSizer.Add(item = self.value,
+                      pos = (1, 1))
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Description")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (2, 0))
+        gridSizer.Add(item = self.desc,
+                      pos = (2, 1), span = (1, 3))
+        addSizer.Add(item = gridSizer)
+        addSizer.Add(item = self.btnAdd, proportion = 0,
+                     flag = wx.TOP | wx.ALIGN_RIGHT, border = 5)
+
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOk)
+        btnSizer.Realize()
+
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = listSizer, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        mainSizer.Add(item = addSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALIGN_CENTER |
+                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        self.SetAutoLayout(True)
+        
+        # set min size for dialog
+        self.SetMinSize(self.GetBestSize())
+        
+    def GetListCtrl(self):
+        """!Used by ColumnSorterMixin"""
+        return self.list
+    
+    def OnText(self, event):
+        """!Text entered"""
+        if self.name.GetValue():
+            self.btnAdd.Enable()
+        else:
+            self.btnAdd.Enable(False)
+        
+    def OnAdd(self, event):
+        """!Add new variable to the list"""
+        msg = self.list.Append(self.name.GetValue(),
+                               self.type.GetStringSelection(),
+                               self.value.GetValue(),
+                               self.desc.GetValue())
+        self.name.SetValue('')
+        self.name.SetFocus()
+        
+        if msg:
+            GMessage(parent = self,
+                     message = msg)
+        else:
+            self.type.SetSelection(0)
+            self.value.SetValue('')
+            self.desc.SetValue('')
+        
+    def OnRightUp(self, event):
+        """!Mouse right button up"""
+        if not hasattr(self, "popupID1"):
+            self.popupID1 = wx.NewId()
+            self.popupID2 = wx.NewId()
+            self.popupID3 = wx.NewId()
+            self.Bind(wx.EVT_MENU, self.list.OnRemove,    id = self.popupID1)
+            self.Bind(wx.EVT_MENU, self.list.OnRemoveAll, id = self.popupID2)
+            self.Bind(wx.EVT_MENU, self.OnReload,    id = self.popupID3)
+        
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupID1, _("Delete selected"))
+        menu.Append(self.popupID2, _("Delete all"))
+        if self.list.GetFirstSelected() == -1:
+            menu.Enable(self.popupID1, False)
+            menu.Enable(self.popupID2, False)
+        
+        menu.AppendSeparator()
+        menu.Append(self.popupID3, _("Reload"))
+        
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+    def OnReload(self, event):
+        """!Reload list of variables"""
+        self.list.Populate(self.parent.GetModel().GetVariables())
+        
+    def OnOK(self, event):
+        """!Store variables to the model"""
+        self.parent.GetModel().SetVariables(self.list.GetData())
+        self.Destroy()
+        
+class VariablesListCtrl(wx.ListCtrl,
+                        listmix.ListCtrlAutoWidthMixin,
+                        listmix.TextEditMixin):
+    def __init__(self, parent, id = wx.ID_ANY, **kwargs):
+        """!List of model variables"""
+        self.parent = parent
+        
+        wx.ListCtrl.__init__(self, parent, id = id, **kwargs)
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        listmix.TextEditMixin.__init__(self)
+
+        self.InsertColumn(0, _("Name"))
+        self.InsertColumn(1, _("Data type"))
+        self.InsertColumn(2, _("Default value"))
+        self.InsertColumn(3, _("Description"))
+        for i in range(0, self.GetColumnCount()):
+            self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
+        
+        self.itemData  = {} # requested by sorter
+        self.itemCount = 0
+
+    def GetData(self):
+        """!Get list data"""
+        return self.itemData
+    
+    def Populate(self, data):
+        """!Populate the list"""
+        self.itemData = copy.deepcopy(data)
+        self.itemCount = len(self.itemData.keys())
+        self.DeleteAllItems()
+        i = 0
+        for name, vtype, value, desc in self.itemData.itervalues():
+            index = self.InsertStringItem(sys.maxint, name)
+            self.SetStringItem(index, 0, name)
+            self.SetStringItem(index, 1, vtype)
+            self.SetStringItem(index, 2, value)
+            self.SetStringItem(index, 3, desc)
+            self.SetItemData(index, i)
+            i += 1
+        
+    def Append(self, name, vtype, value, desc):
+        """!Append new item to the list
+
+        @return None on success
+        @return error string
+        """
+        for iname, ivtype, ivalue, idesc in self.itemData.itervalues():
+            if iname == name:
+                return _("Variable <%s> already exists in the model. "
+                         "Adding variable failed.") % name
+        
+        index = self.InsertStringItem(sys.maxint, name)
+        self.SetStringItem(index, 0, name)
+        self.SetStringItem(index, 1, vtype)
+        self.SetStringItem(index, 2, value)
+        self.SetStringItem(index, 3, desc)
+        self.SetItemData(index, self.itemCount)
+        
+        self.itemData[self.itemCount] = (name, vtype, value, desc)
+        self.itemCount += 1
+        
+        return None
+
+    def OnRemove(self, event):
+        """!Remove selected variable(s) from the model"""
+        item = self.GetFirstSelected()
+        while item != -1:
+            self.DeleteItem(item)
+            del self.itemData[item]
+            item = self.GetFirstSelected()
+        event.Skip()
+    
+    def OnRemoveAll(self, event):
+        """!Remove all variable(s) from the model"""
+        self.DeleteAllItems()
+        self.itemData = dict()
     
     
 def main():
 def main():
     app = wx.PySimpleApp()
     app = wx.PySimpleApp()

+ 1 - 0
gui/wxpython/gui_modules/vdigit.py

@@ -16,6 +16,7 @@ Classes:
  - CDisplayDriver
  - CDisplayDriver
  - VDigitSettingsDialog
  - VDigitSettingsDialog
  - VDigitCategoryDialog
  - VDigitCategoryDialog
+ - CategoryListCtrl
  - VDigitZBulkDialog
  - VDigitZBulkDialog
  - VDigitDuplicatesDialog
  - VDigitDuplicatesDialog
  - VDigitVBuildDialog
  - VDigitVBuildDialog

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

@@ -14,7 +14,7 @@
 
 
 <!ELEMENT grass-gxm (gxm)>
 <!ELEMENT grass-gxm (gxm)>
 
 
-<!ELEMENT gxm (action*, data*)>
+<!ELEMENT gxm (action*, data*, properties?, variable*)>
 
 
 <!--    an action defines action properties (usually GRASS modules)
 <!--    an action defines action properties (usually GRASS modules)
 -->
 -->
@@ -80,3 +80,15 @@
 <!ELEMENT point  (x, y)>
 <!ELEMENT point  (x, y)>
 <!ELEMENT x      (#PCDATA)>
 <!ELEMENT x      (#PCDATA)>
 <!ELEMENT y      (#PCDATA)>
 <!ELEMENT y      (#PCDATA)>
+
+<!--	a properties describes model properties
+-->
+<!ELEMENT properties    (name?, description?, author?, flag*)>
+<!ELEMENT name          (#PCDATA)>
+<!ELEMENT description   (#PCDATA)>
+<!ELEMENT author        (#PCDATA)>
+
+<!--	a variable describes model variable
+-->
+<!ELEMENT variable        (name, description?, value?)>
+<!ATTLIST variable  type  (integer | float | string) #REQUIRED>