[GRASS-SVN] r50006 - in grass/trunk/gui/wxpython: . dbmgr gui_core

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Dec 31 09:16:46 EST 2011


Author: martinl
Date: 2011-12-31 06:16:46 -0800 (Sat, 31 Dec 2011)
New Revision: 50006

Modified:
   grass/trunk/gui/wxpython/dbmgr/dialogs.py
   grass/trunk/gui/wxpython/dbmgr/manager.py
   grass/trunk/gui/wxpython/gui_core/widgets.py
   grass/trunk/gui/wxpython/wxpythonlib.dox
Log:
wxGUI: modify attribute records - better error tracking (validators + don't close on errors)


Modified: grass/trunk/gui/wxpython/dbmgr/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/dbmgr/dialogs.py	2011-12-31 13:43:47 UTC (rev 50005)
+++ grass/trunk/gui/wxpython/dbmgr/dialogs.py	2011-12-31 14:16:46 UTC (rev 50006)
@@ -16,15 +16,17 @@
 """
 
 import os
+import types
 
 from core import globalvar
 import wx
 import wx.lib.scrolledpanel as scrolled
 
-from core.gcmd     import RunCommand
-from core.debug    import Debug
-from core.settings import UserSettings
-from dbmgr.vinfo   import VectorDBInfo
+from core.gcmd        import RunCommand, GError
+from core.debug       import Debug
+from core.settings    import UserSettings
+from dbmgr.vinfo      import VectorDBInfo
+from gui_core.widgets import IntegerValidator, FloatValidator
 
 class DisplayAttributesDialog(wx.Dialog):
     def __init__(self, parent, map,
@@ -158,11 +160,12 @@
 
         # set min size for dialog
         w, h = self.GetBestSize()
+        w += 50
         if h < 200:
             self.SetMinSize((w, 200))
         else:
-            self.SetMinSize(self.GetBestSize())
-
+            self.SetMinSize((w, h))
+        
         if self.notebook.GetPageCount() == 0:
             Debug.msg(2, "DisplayAttributesDialog(): Nothing found!")
             ### self.mapDBInfo = None
@@ -182,6 +185,8 @@
     def GetSQLString(self, updateValues = False):
         """!Create SQL statement string based on self.sqlStatement
 
+        Show error message when invalid values are entered.
+        
         If updateValues is True, update dataFrame according to values
         in textfields.
         """
@@ -198,26 +203,38 @@
                     if name == key:
                         cat = columns[name]['values'][idx]
                         continue
-                    type  = columns[name]['type']
+                    ctype  = columns[name]['ctype']
                     value = columns[name]['values'][idx]
                     id    = columns[name]['ids'][idx]
                     try:
                         newvalue = self.FindWindowById(id).GetValue()
                     except:
                         newvalue = self.FindWindowById(id).GetLabel()
-
-                    if newvalue == '':
-                        newvalue = None
                     
+                    try:
+                        if ctype == int:
+                            newvalue = int(newvalue)
+                        elif ctype == float:
+                            newvalue = float(newvalue)
+                    except ValueError:
+                        GError(parent = self,
+                               message = _("Column <%(col)s>: Value '%(value)s' needs to be entered as %(type)s.") % \
+                                   {'col' : name,
+                                    'value' : str(newvalue),
+                                    'type' : columns[name]['type'].lower()},
+                               showTraceback = False)
+                        sqlCommands.append(None)
+                        continue
+                    
                     if newvalue != value:
                         updatedColumns.append(name)
                         if newvalue is None:
                             updatedValues.append('NULL')
                         else:
-                            if type != 'character':
-                                updatedValues.append(newvalue)
+                            if ctype != str:
+                                updatedValues.append(str(newvalue))
                             else:
-                                updatedValues.append("'" + newvalue + "'")
+                                updatedValues.append("'" + str(newvalue) + "'")
                         columns[name]['values'][idx] = newvalue
 
                 if self.action != "add" and len(updatedValues) == 0:
@@ -289,13 +306,18 @@
     def OnSubmit(self, event):
         """!Submit records"""
         layer = 1
+        close = True
+        enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
+        if not enc and 'GRASS_DB_ENCODING' in os.environ:
+            enc = os.environ['GRASS_DB_ENCODING']
+        
         for sql in self.GetSQLString(updateValues = True):
-            enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
-            if not enc and 'GRASS_DB_ENCODING' in os.environ:
-                enc = os.environ['GRASS_DB_ENCODING']
+            if not sql:
+                close = False
+                continue
             if enc:
                 sql = sql.encode(enc)
-
+            
             driver, database = self.mapDBInfo.GetDbSettings(layer)
             Debug.msg(1, "SQL: %s" % sql)
             RunCommand('db.execute',
@@ -308,7 +330,7 @@
             
             layer += 1
         
-        if self.closeDialog.IsChecked():
+        if close and self.closeDialog.IsChecked():
             self.OnCancel(event)
 
     def OnFeature(self, event):
@@ -462,8 +484,8 @@
                 # notebook body
                 border = wx.BoxSizer(wx.VERTICAL)
                 
-                flexSizer = wx.FlexGridSizer (cols = 4, hgap = 3, vgap = 3)
-                flexSizer.AddGrowableCol(3)
+                flexSizer = wx.FlexGridSizer (cols = 3, hgap = 3, vgap = 3)
+                flexSizer.AddGrowableCol(2)
                 # columns (sorted by index)
                 names = [''] * len(columns.keys())
                 for name in columns.keys():
@@ -473,10 +495,11 @@
                     if name == key: # skip key column (category)
                         continue
                     
-                    vtype  = columns[name]['type']
+                    vtype  = columns[name]['type'].lower()
+                    ctype  = columns[name]['ctype']
                     
                     if columns[name]['values'][idx] is not None:
-                        if columns[name]['ctype'] != type(''):
+                        if columns[name]['ctype'] != types.StringType:
                             value = str(columns[name]['values'][idx])
                         else:
                             value = columns[name]['values'][idx]
@@ -486,21 +509,22 @@
                     colName = wx.StaticText(parent = panel, id = wx.ID_ANY,
                                             label = name)
                     colType = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                            label = "[" + vtype.lower() + "]")
-                    delimiter = wx.StaticText(parent = panel, id = wx.ID_ANY, label = ":")
-                    
+                                            label = "[%s]:" % vtype)
                     colValue = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = value)
                     colValue.SetName(name)
+                    if ctype == int:
+                        colValue.SetValidator(IntegerValidator())
+                    elif ctype == float:
+                        colValue.SetValidator(FloatValidator())
+                    
                     self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue)
                     if self.action == 'display':
                         colValue.SetWindowStyle(wx.TE_READONLY)
                     
                     flexSizer.Add(colName, proportion = 0,
-                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+                                  flag = wx.ALIGN_CENTER_VERTICAL)
                     flexSizer.Add(colType, proportion = 0,
-                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-                    flexSizer.Add(delimiter, proportion = 0,
-                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+                                  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
                     flexSizer.Add(colValue, proportion = 1,
                                   flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
                     # add widget reference to self.columns
@@ -568,7 +592,7 @@
         self.cat = None
         winFocus = False
         
-        for column, ctype, value in data:
+        for column, ctype, ctypeStr, value in data:
             if self.keyId == cId:
                 self.cat = int(value)
                 if not keyEditable[1]:
@@ -584,6 +608,10 @@
             else:
                 valueWin = wx.TextCtrl(parent = self.dataPanel, id = wx.ID_ANY,
                                        value = value, size = (250, -1))
+                if ctype == int:
+                    valueWin.SetValidator(IntegerValidator())
+                elif ctype == float:
+                    valueWin.SetValidator(FloatValidator())
                 if not winFocus:
                     wx.CallAfter(valueWin.SetFocus)
                     winFocus = True
@@ -591,7 +619,7 @@
             label = wx.StaticText(parent = self.dataPanel, id = wx.ID_ANY,
                                   label = column)
             ctype = wx.StaticText(parent = self.dataPanel, id = wx.ID_ANY,
-                                  label = "[%s]:" % ctype)
+                                  label = "[%s]:" % ctypeStr.lower())
             self.widgets.append((label.GetId(), ctype.GetId(), valueWin.GetId()))
             
             cId += 1

Modified: grass/trunk/gui/wxpython/dbmgr/manager.py
===================================================================
--- grass/trunk/gui/wxpython/dbmgr/manager.py	2011-12-31 13:43:47 UTC (rev 50005)
+++ grass/trunk/gui/wxpython/dbmgr/manager.py	2011-12-31 14:16:46 UTC (rev 50006)
@@ -499,7 +499,7 @@
             item1 = self.itemDataMap[key1][self._col]
             item2 = self.itemDataMap[key2][self._col]
 
-        if type(item1) == type('') or type(item2) == type(''):
+        if type(item1) == types.StringType or type(item2) == types.StringTypes:
             cmpVal = locale.strcoll(str(item1), str(item2))
         else:
             cmpVal = cmp(item1, item2)
@@ -1352,13 +1352,14 @@
         colIdx = 0
         keyId = -1
         for col in columnName:
-            ctype = self.mapDBInfo.tables[table][col]['type']
+            ctype = self.mapDBInfo.tables[table][col]['ctype']
+            ctypeStr = self.mapDBInfo.tables[table][col]['type']
             if col == keyColumn: # key 
                 if missingKey is False: 
-                    data.append((col, ctype, str(maxCat + 1)))
+                    data.append((col, ctype, ctypeStr, str(maxCat + 1)))
                     keyId = colIdx
             else:
-                data.append((col, ctype, ''))
+                data.append((col, ctype, ctypeStr, ''))
             
             colIdx += 1
                 
@@ -1409,10 +1410,11 @@
 
             except ValueError, err:
                 GError(parent = self,
-                       message = "%s%s%s" % (_("Unable to insert new record."),
-                                             os.linesep, err))
+                       message = _("Unable to insert new record.\n%s") % err,
+                       showTraceback = False)
+                self.OnDataItemAdd(event)
                 return
-
+            
             # remove category if need 
             if missingKey is True:
                 del values[0]
@@ -1465,17 +1467,18 @@
             
         # add other visible columns
         for i in range(len(columnName)):
-            ctype = self.mapDBInfo.tables[table][columnName[i]]['type']
+            ctype = self.mapDBInfo.tables[table][columnName[i]]['ctype']
+            ctypeStr = self.mapDBInfo.tables[table][columnName[i]]['type']
             if columnName[i] == keyColumn: # key 
                 if missingKey is False: 
-                    data.append((columnName[i], ctype, str(cat)))
+                    data.append((columnName[i], ctype, ctypeStr, str(cat)))
                     keyId = i
             else:
                 if missingKey is True:
                     value = tlist.GetItem(item, i-1).GetText()
                 else:
                     value = tlist.GetItem(item, i).GetText()
-                data.append((columnName[i], ctype, value))
+                data.append((columnName[i], ctype, ctypeStr, value))
 
         dlg = ModifyTableRecord(parent = self, 
                                 title = _("Update existing record"),
@@ -1495,7 +1498,7 @@
                                     idx = i - 1
                                 else:
                                     idx = i
-                                if tlist.columns[columnName[i]]['ctype'] != type(''):
+                                if tlist.columns[columnName[i]]['ctype'] != types.StringType:
                                     if tlist.columns[columnName[i]]['ctype'] == int:
                                         value = float(values[i])
                                     else:
@@ -1518,8 +1521,9 @@
                             
             except ValueError, err:
                 GError(parent = self,
-                       message = "%s%s%s" % (_("Unable to update existing record."),
-                                             os.linesep, err))
+                       message = _("Unable to update existing record.\n%s") % err,
+                       showTraceback = False)
+                self.OnDataItemEdit(event)
                 return
             
             if len(updateString) > 0:

Modified: grass/trunk/gui/wxpython/gui_core/widgets.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/widgets.py	2011-12-31 13:43:47 UTC (rev 50005)
+++ grass/trunk/gui/wxpython/gui_core/widgets.py	2011-12-31 14:16:46 UTC (rev 50006)
@@ -6,11 +6,12 @@
 Classes:
  - widgets::GNotebook
  - widgets::ScrolledPanel
- - widgets::NTCValidator
  - widgets::NumTextCtrl
  - widgets::FloatSlider
  - widgets::SymbolButton
  - widgets::StaticWrapText
+ - widgets::BaseValidator
+ - widgets::IntegerValidator
  - widgets::FloatValidator
  - widgets::ItemTree
 
@@ -97,31 +98,6 @@
     def OnChildFocus(self, event):
         pass
         
-        
-class NTCValidator(wx.PyValidator):
-    """!validates input in textctrls, taken from wxpython demo"""
-    def __init__(self, flag = None):
-        wx.PyValidator.__init__(self)
-        self.flag = flag
-        self.Bind(wx.EVT_CHAR, self.OnChar)
-
-    def Clone(self):
-        return NTCValidator(self.flag)
-
-    def OnChar(self, event):
-        key = event.GetKeyCode()
-        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
-            event.Skip()
-            return
-        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.-':
-            event.Skip()
-            return
-        if not wx.Validator_IsSilent():
-            wx.Bell()
-        # Returning without calling even.Skip eats the event before it
-        # gets to the text control
-        return  
-    
 class NumTextCtrl(wx.TextCtrl):
     """!Class derived from wx.TextCtrl for numerical values only"""
     def __init__(self, parent,  **kwargs):
@@ -271,17 +247,18 @@
                 self.SetSize(self.wrappedSize)
             del self.resizing
 
-class FloatValidator(wx.PyValidator):
-    """!Validator for floating-point input"""
+class BaseValidator(wx.PyValidator):
     def __init__(self):
         wx.PyValidator.__init__(self)
         
         self.Bind(wx.EVT_TEXT, self.OnText) 
+
+    def OnText(self, event):
+        """!Do validation"""
+        self.Validate()
         
-    def Clone(self):
-        """!Clone validator"""
-        return FloatValidator()
-
+        event.Skip()
+        
     def Validate(self):
         """Validate input"""
         textCtrl = self.GetWindow()
@@ -289,7 +266,7 @@
 
         if text:
             try:
-                float(text)
+                self.type(text)
             except ValueError:
                 textCtrl.SetBackgroundColour("grey")
                 textCtrl.SetFocus()
@@ -303,18 +280,56 @@
         
         return True
 
-    def OnText(self, event):
-        """!Do validation"""
-        self.Validate()
-        
-        event.Skip()
-        
     def TransferToWindow(self):
         return True # Prevent wxDialog from complaining.
     
     def TransferFromWindow(self):
         return True # Prevent wxDialog from complaining.
 
+class IntegerValidator(BaseValidator):
+    """!Validator for floating-point input"""
+    def __init__(self):
+        BaseValidator.__init__(self)
+        self.type = int
+        
+    def Clone(self):
+        """!Clone validator"""
+        return IntegerValidator()
+
+class FloatValidator(BaseValidator):
+    """!Validator for floating-point input"""
+    def __init__(self):
+        BaseValidator.__init__(self)
+        self.type = float
+        
+    def Clone(self):
+        """!Clone validator"""
+        return FloatValidator()
+
+class NTCValidator(wx.PyValidator):
+    """!validates input in textctrls, taken from wxpython demo"""
+    def __init__(self, flag = None):
+        wx.PyValidator.__init__(self)
+        self.flag = flag
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+
+    def Clone(self):
+        return NTCValidator(self.flag)
+
+    def OnChar(self, event):
+        key = event.GetKeyCode()
+        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
+            event.Skip()
+            return
+        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.-':
+            event.Skip()
+            return
+        if not wx.Validator_IsSilent():
+            wx.Bell()
+        # Returning without calling even.Skip eats the event before it
+        # gets to the text control
+        return  
+    
 class ItemTree(CT.CustomTreeCtrl):
     def __init__(self, parent, id = wx.ID_ANY,
                  ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |

Modified: grass/trunk/gui/wxpython/wxpythonlib.dox
===================================================================
--- grass/trunk/gui/wxpython/wxpythonlib.dox	2011-12-31 13:43:47 UTC (rev 50005)
+++ grass/trunk/gui/wxpython/wxpythonlib.dox	2011-12-31 14:16:46 UTC (rev 50006)
@@ -168,7 +168,10 @@
  - widgets::FloatSlider
  - widgets::SymbolButton
  - widgets::StaticWrapText
+ - widgets::BaseValidator
+ - widgets::IntegerValidator
  - widgets::FloatValidator
+ - widgets::NTCValidator
  - widgets::ItemTree
 
 \subsection lmgr Layer Manager



More information about the grass-commit mailing list