dabo Commit
Revision 4986
Date: 2009-01-28 19:35:04 -0800 (Wed, 28 Jan 2009)
Author: Ed
Trac: http://trac.dabodev.com/changeset/4986

Changed:
U   trunk/dabo/biz/dBizobj.py
U   trunk/dabo/db/dCursorMixin.py
U   trunk/dabo/db/dDataSet.py
U   trunk/dabo/ui/uiwx/dForm.py

Log:
Added the ability to filter data in the current dataset without requerying the 
database. In order to ensure that the UI is properly updated, you should call 
dForm.filter().

There are still issues to resolve when using filter(). One situation is if you 
change a record, and then apply a filter that 'removes' that record from the 
current data set. Most of our scan routines are based on RowNumber, and this is 
completely broken by filtering. So for now I'm adding this with the warning 
that some things affected by this are not rock-solid by any means.



Diff:
Modified: trunk/dabo/biz/dBizobj.py
===================================================================
--- trunk/dabo/biz/dBizobj.py   2009-01-28 22:33:33 UTC (rev 4985)
+++ trunk/dabo/biz/dBizobj.py   2009-01-29 03:35:04 UTC (rev 4986)
@@ -757,6 +757,8 @@
                else:
                        cursors = {old_currentCursorKey: currCursor}
 
+               dabo.trace()
+
                for key, cursor in cursors.iteritems():
                        self._CurrentCursor = key
                        changedRows = self.getChangedRows(includeNewUnchanged)
@@ -966,6 +968,47 @@
                self.__params = params
 
 
+       def filter(self, fld, expr, op="="):
+               """
+               This takes a field name, an expression, and an optional 
operator, and applies that 
+               to the current dataset. The original dataset is preserved; 
calling removeFilter() will 
+               remove the last filter applied to the bizobj. If the current 
record is in the filtered 
+               dataset, that record will still be current; if it is filtered 
out, the current row will 
+               be row 0.
+               If the operator is specified, it will be used literally in the 
evaluation instead of the 
+               equals sign, unless it is one of the following strings, which 
will be interpreted 
+               as indicated:
+                       eq, equals: =
+                       ne, nequals: !=
+                       gt: >
+                       gte: >=
+                       lt: <
+                       lte: <=
+                       startswith, beginswith: fld.startswith(expr)
+                       endswith: fld.endswith(expr)
+                       contains: expr in fld
+               """
+               currPK = self.getPK()
+               self._CurrentCursor.filter(fld=fld, expr=expr, op=op)
+               newPK = self.getPK()
+               if newPK != currPK:
+                       try:
+                               self.moveToPK(currPK)
+                       except dabo.dException.RowNotFoundException:
+                               # The old row was filtered out of the dataset
+                               self.first()
+
+
+       def removeFilter(self):
+               """Remove the most recently applied filter."""
+               self._CurrentCursor.removeFilter()
+
+
+       def removeFilters(self):
+               """Remove all applied filters, going back to the original data 
set."""
+               self._CurrentCursor.removeFilters()
+
+
        def _validate(self):
                """ Internal method. User code should override validateRecord().
 

Modified: trunk/dabo/db/dCursorMixin.py
===================================================================
--- trunk/dabo/db/dCursorMixin.py       2009-01-28 22:33:33 UTC (rev 4985)
+++ trunk/dabo/db/dCursorMixin.py       2009-01-29 03:35:04 UTC (rev 4986)
@@ -165,7 +165,7 @@
                """Returns the PK expression for the passed record."""
                if rec is None:
                        try:
-                               rec = self._records[self.RowNumber]
+                               rec = 
self._records.UnfilteredDataSet[self.RowNumber]
                        except IndexError:
                                rec = {}
                if isinstance(self.KeyField, tuple):
@@ -372,11 +372,8 @@
                                                                field_name=fld, 
_newQuery=_newQuery)
 
                self._records = dDataSet(_records)
-               if self.RowCount > 0:
-                       self.RowNumber = max(0, self.RowNumber)
-                       maxrow = max(0, (self.RowCount-1) )
-                       self.RowNumber = min(self.RowNumber, maxrow)
-
+               # This will handle bounds issues
+               self.RowNumber = self.RowNumber
                return res
 
 
@@ -816,7 +813,6 @@
                        raise dException.NoRecordsException(_("No records in 
the data set."))
                if row is None:
                        row = self.RowNumber
-
                try:
                        rec = self._records[row]
                except IndexError:
@@ -1140,7 +1136,7 @@
                """Creates a copy of the current record and adds it to the 
dataset."""
                if not self.RowCount:
                        raise dException.NoRecordsException(_("No records in 
the data set."))
-               rec = self._records[self.RowNumber]
+               rec = self._records[self.RowNumber].copy()
                if self.AutoPopulatePK:
                        kf = self.KeyField
                        blank = self._getBlankRecord()
@@ -1180,6 +1176,21 @@
                                pass
 
 
+       def filter(self, fld, expr, op="="):
+               """Apply a filter to the current records."""
+               self._records = self._records.filter(fld=fld, expr=expr, op=op)
+
+
+       def removeFilter(self):
+               """Remove the most recently applied filter."""
+               self._records = self._records.removeFilter()
+
+
+       def removeFilters(self):
+               """Remove all applied filters, going back to the original data 
set."""
+               self._records = self._records.removeFilters()
+
+
        def replace(self, field, valOrExpr, scope=None):
                """Replaces the value of the specified field with the given 
value
                or expression. All records matching the scope are affected; if
@@ -1189,11 +1200,10 @@
                with an equals sign. All expressions will therefore be a string
                beginning with '='. Literals can be of any type.
                """
-               if isinstance(self._records, dDataSet):
-                       # Make sure that the data set object has any necessary 
references
-                       self._records.Cursor = self
-                       self._records.Bizobj = self._bizobj
-                       self._records.replace(field, valOrExpr, scope=scope)
+               # Make sure that the data set object has any necessary 
references
+               self._records.Cursor = self
+               self._records.Bizobj = self._bizobj
+               self._records.replace(field, valOrExpr, scope=scope)
 
 
        def first(self):
@@ -1287,6 +1297,10 @@
                rec = self._records[row]
                recKey = self.pkExpression(rec)
                newrec = kons.CURSOR_TMPKEY_FIELD in rec
+               
+               print "newrec = ", newrec
+               print "recKey = ", recKey
+               
                newPKVal = None
                if newrec and self.AutoPopulatePK:
                        # Some backends do not provide a means to retrieve
@@ -1505,7 +1519,7 @@
 
                # Faster to deal with 2 specific cases: all rows or just 
current row
                if allRows:
-                       recs = self._records
+                       recs = self._records.UnfilteredDataSet
 
                        if self._newRecords:
                                recs = list(recs)
@@ -2490,14 +2504,16 @@
 
        def _getRowNumber(self):
                try:
-                       ret = self.__rownumber
+                       ret = min(self.__rownumber, self._getRowCount()-1)
                except AttributeError:
                        ret = -1
                return ret
 
 
        def _setRowNumber(self, num):
-               self.__rownumber = num
+               rn = max(0, num)
+               maxrow = max(0, (self.RowCount-1) )
+               self.__rownumber = min(rn, maxrow)
 
 
        def _getTable(self):

Modified: trunk/dabo/db/dDataSet.py
===================================================================
--- trunk/dabo/db/dDataSet.py   2009-01-28 22:33:33 UTC (rev 4985)
+++ trunk/dabo/db/dDataSet.py   2009-01-29 03:35:04 UTC (rev 4986)
@@ -192,6 +192,9 @@
                        stmnt = "select * from dataset where %s %s" % (fld, 
clause)
                        ret = self.execute(stmnt, (param, ))
                ret._sourceDataSet = self
+               ret._filtered_fld = fld
+               ret._filtered_expr = expr
+               ret._filtered_op = op
                return ret
 
 
@@ -420,6 +423,13 @@
                        pass
 
 
+       def _getUnfilteredDataSet(self):
+               ret = self
+               while ret._sourceDataSet:
+                       ret = ret._sourceDataSet
+               return ret
+
+
        Bizobj = property(_getBizobj, _setBizobj, None,
                        _("Reference to the bizobj that 'owns' this data set. 
Default=None  (bizobj)"))
 
@@ -429,9 +439,12 @@
        Encoding = property(_getEncoding, _setEncoding, None,
                        _(" The encoding used for data in the dataset.  (str)"))
 
+       UnfilteredDataSet = property(_getUnfilteredDataSet, None, None,
+                       _("""If filters have been applied, returns the 
unfiltered dataset that would be returned if removeFilters() had been called. 
If no filters have been applied, returns self  (dDataSet)"""))
 
 
 
+
 # class DataSetOld(tuple):
 #      """ This class assumes that its contents are not ordinary tuples, but
 #      rather tuples consisting of dicts, where the dict keys are field names.

Modified: trunk/dabo/ui/uiwx/dForm.py
===================================================================
--- trunk/dabo/ui/uiwx/dForm.py 2009-01-28 22:33:33 UTC (rev 4985)
+++ trunk/dabo/ui/uiwx/dForm.py 2009-01-29 03:35:04 UTC (rev 4986)
@@ -275,6 +275,7 @@
                self._moveRecordPointer(bizobj.first, dataSource)
                self.afterFirst()
 
+
        def last(self, dataSource=None):
                """ Ask the bizobj to move to the last record."""
                bizobj = self.getBizobj(dataSource)
@@ -288,6 +289,7 @@
                self._moveRecordPointer(bizobj.last, dataSource)
                self.afterLast()
 
+
        def prior(self, dataSource=None):
                """ Ask the bizobj to move to the previous record."""
                bizobj = self.getBizobj(dataSource)
@@ -300,7 +302,8 @@
                        return
                self._moveRecordPointer(bizobj.prior, dataSource)
                self.afterPrior()
-               
+
+
        def next(self, dataSource=None):
                """ Ask the bizobj to move to the next record."""
                bizobj = self.getBizobj(dataSource)
@@ -315,6 +318,41 @@
                self.afterNext()
                
 
+       def filter(self, dataSource=None, fld=None, expr=None, op="="):
+               """Apply a filter to the bizobj's data."""
+               bizobj = self.getBizobj(dataSource)
+               if bizobj is None:
+                       # Running in preview or some other non-live mode
+                       return
+               # Make sure that they passed 'fld' and 'expr'
+               if fld is None or expr is None:
+                       raise ValueError(_("Both 'fld' and 'expr' need to be 
supplied to the call to filter()."))
+               err = self.beforeFilter()
+               if err:
+                       self.notifyUser(err)
+                       return
+               self._moveRecordPointer(bizobj.filter, dataSource, fld=fld, 
expr=expr, op=op)
+               self.afterFilter()
+
+
+       def removeFilter(self, dataSource=None):
+               """Remove the most recently applied filter from the bizobj's 
data."""
+               bizobj = self.getBizobj(dataSource)
+               if bizobj is None:
+                       # Running in preview or some other non-live mode
+                       return
+               self._moveRecordPointer(bizobj.removeFilter, dataSource)
+               
+
+       def removeFilters(self, dataSource=None):
+               """Remove all filters from the bizobj's data."""
+               bizobj = self.getBizobj(dataSource)
+               if bizobj is None:
+                       # Running in preview or some other non-live mode
+                       return
+               self._moveRecordPointer(bizobj.removeFilters, dataSource)
+               
+
        def save(self, dataSource=None):
                """ Ask the bizobj to commit its changes to the backend."""
                bizobj = self.getBizobj(dataSource)
@@ -666,7 +704,8 @@
        def beforeLast(self): pass
        def beforePrior(self): pass
        def beforeNext(self): pass
-       def beforeSave(self): pass
+       def beforeNext(self): pass
+       def beforeFilter(self): pass
        def beforeCancel(self): pass
        def beforeRequery(self): pass
        def beforeDelete(self): pass
@@ -677,6 +716,7 @@
        def afterLast(self): pass
        def afterPrior(self): pass
        def afterNext(self): pass
+       def afterFilter(self): pass
        def afterSave(self): pass
        def afterCancel(self): pass
        def afterRequery(self): pass



_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev
Searchable Archives: http://leafe.com/archives/search/dabo-dev
This message: 
http://leafe.com/archives/byMID/[email protected]

Reply via email to