Changeset 52

Show
Ignore:
Timestamp:
03/09/04 07:32:35 (5 years ago)
Author:
paul
Message:

Rework minor parts of Ed's files (mostly
just the import lines) to fit in with the
new directory structure. Delete the temp
_p files that constituted my changes.

The next step will be to remove the current
trunk and replace with the branch, and from
then on all work will be in the trunk instead
of in the branch.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/paulRefactor/biz/dBizobj.py

    r51 r52  
    1 from dConstants import dConstants as k 
    2 import dConnection 
    3 import dCursorMixin 
     1import dabo.dConstants as k 
     2import dabo.db.dConnection as dConnection 
     3from dabo.db.dCursorMixin import dCursorMixin 
    44import types 
    55 
    6  
    7 ### TODO ### - Change to Gadfly 
    8 from MySQLdb import cursors 
    9  
    10 class dBizobj: 
    11    # Title of the cursor. Used in resolving DataSource reference
    12     dataSource = "" 
    13     # SQL statement used to create the cursor's data 
    14     sql = "" 
    15     # When true, the cursor object does not run its query immediately. This 
    16     # is useful for parameterized queries 
    17     noDataOnLoad = 0 
    18     # Holds the params to be merged with the sql in the cursor 
    19     _params = () 
    20     # Reference to the cursor object  
    21     _cursor = None 
    22     # Class to instantiate for the cursor object 
    23     cursorMixinClass = dCursorMixin.dCursorMixin 
    24    # Base class to instantiate for the cursor objec
    25     ### TODO ### - change to Gadfly for default 
    26     #cursorBaseClass = cursors.DictCursor 
    27     cursorBaseClass = cursors.Cursor 
    28     # Reference to the parent bizobj to this one. 
    29     _parent = None 
    30     # Collection of child bizobjs for this 
    31     __children = [] 
    32     # Name of field that is the PK  
    33     keyField = "" 
    34     # Name of field that is the FK back to the parent 
    35     linkField = "" 
    36     # Holds any error messages generated during a process 
    37     _errorMsg = "" 
    38     # Dictionary holding any default values to apply when a new record is created 
    39     defaultValues = {}       
    40     # Do we requery child bizobjs after a Save()? 
    41     requeryChildOnSave = 1 
    42     # Should new child records be added when a new parent record is added? 
    43     newChildOnNew = 0 
    44     # If this bizobj's parent has newChildOnNew =1, do we create a record here? 
    45     newRecordOnNewParent = 0 
    46     # In the onNew() method, do we fill in the linkField with the value returned by calling the parent 
    47     # bizobj's GetKeyValue() method? 
    48     fillLinkFromParent = 0 
    49     # After a requery, do we try to restore the record position to the same PK? 
    50     savePosOnRequery = 1 
    51      
    52    ########################################## 
    53     ### referential integrity stuff #### 
    54     ########################################## 
    55     ### Possible values for each type (not all are relevant for each action): 
    56     ### IGNORE - don't worry about the presence of child records 
    57     ### RESTRICT - don't allow action if there are child records 
    58     ### CASCADE - changes to the parent are cascaded to the children 
    59     deleteChildLogic = k.REFINTEG_CASCADE       # child records will be deleted 
    60     updateChildLogic = k.REFINTEG_IGNORE    # parent keys can be changed w/o affecting children 
    61     insertChildLogic = k.REFINTEG_IGNORE        # child records can be inserted even if no parent record exists. 
    62     ########################################## 
    63     # Versioning... 
    64     _version = "0.1.0" 
    65      
    66      
    67     def __init__(self, conn): 
    68         # Save the connection reference 
    69         self._conn = conn 
    70         # Now create the cursor that this bizobj will be using for data 
    71         if self.beforeCreateCursor(): 
    72             crsClass = self.getCursorClass(self.cursorMixinClass, self.cursorBaseClass) 
    73            self._cursor = conn.cursor(cursorclass=crsClass) 
    74            self._cursor.setSQL(self.sql
    75            self._cursor.setKeyField(self.keyField
    76            self._cursor.setTable(self.dataSource
    77             if not self.noDataOnLoad: 
    78                 self._cursor.requery() 
    79            self.afterCreateCursor() 
    80              
    81         if not self._cursor: 
    82             ##### TODO  ####### 
    83             # Need to raise an exception here! 
    84             pass 
    85          
    86         # Need to set this so that different instances don't mix up the references 
    87         # contained in this list. 
    88         self.__children = [] 
    89      
    90      
    91     def getCursorClass(self, main, secondary): 
    92        class cursorMix(main, secondary): 
    93             superMixin = main 
    94             superCursor = secondary 
    95             def __init__(self, *args, **kwargs): 
    96                if hasattr(main, "__init__"): 
    97                    apply(main.__init__,(self,) + args, kwargs) 
    98                     #main.__init__(self) 
    99                 if hasattr(secondary, "__init__"): 
    100                     apply(secondary.__init__,(self,) + args, kwargs) 
    101         return  cursorMix 
    102      
    103  
    104          
    105     def first(self): 
    106         """ Moves the record pointer in the cursor to the first record of the result set. 
    107         Updates any child bizobjs to reflect the new current parent record.  
    108         If the record set is already at the beginning, returns k.FILE_BOF. """ 
    109         self._errorMsg = "" 
    110         if not self.beforeFirst() or not self.beforePointerMove(): 
    111             return k.FILE_CANCEL 
    112         ret = self._cursor.first() 
    113          
    114         if ret == k.FILE_OK: 
    115             self.requeryAllChildren() 
    116            self.setMemento(
    117         else: 
    118            self.addToErrorMsg(self._cursor.getErrorMsg()
    119         self.afterPointerMove(ret) 
    120         self.afterFirst(ret) 
    121         return ret 
    122      
    123  
    124     def prior(self): 
    125         """ Moves the record pointer in the cursor back one position in the result set. 
    126        Updates any child bizobjs to reflect the new current parent record.  
    127        If the record set is already at the beginning, returns k.FILE_BOF. """ 
    128        self._errorMsg = "" 
    129        if not self.beforePrior() or not self.beforePointerMove(): 
    130            return k.FILE_CANCEL 
    131        ret = self._cursor.prior() 
    132          
    133        if ret == k.FILE_OK: 
    134            self.requeryAllChildren() 
    135            self.setMemento() 
    136        else: 
    137            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    138        self.afterPointerMove(ret) 
    139        self.afterPrior(ret) 
    140        return ret 
    141      
    142  
    143    def next(self): 
    144        """ Moves the record pointer in the cursor to the next record of the result set. 
    145        Updates any child bizobjs to reflect the new current parent record. 
    146        If the recordset is already at the last record, returns k.FILE_EOF. """ 
    147        self._errorMsg = "" 
    148        if not self.beforeNext() or not self.beforePointerMove(): 
    149            return k.FILE_CANCEL 
    150        ret = self._cursor.next() 
    151          
    152        if ret == k.FILE_OK: 
    153            self.requeryAllChildren() 
    154            self.setMemento() 
    155        else: 
    156            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    157        self.afterPointerMove(ret) 
    158        self.afterNext(ret) 
    159        return ret 
    160      
    161  
    162    def last(self): 
    163        """ Moves the record pointer in the cursor to the last record of the result set. 
    164        Updates any child bizobjs to reflect the new current parent record. 
    165        If the recordset is already at the last record, returns k.FILE_EOF. """ 
    166        self._errorMsg = "" 
    167        if not self.beforeLast() or not self.beforePointerMove(): 
    168            return k.FILE_CANCEL 
    169        ret = self._cursor.last() 
    170          
    171        if ret == k.FILE_OK: 
    172            self.requeryAllChildren() 
    173            self.setMemento() 
    174        else: 
    175            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    176        self.afterPointerMove(ret) 
    177        self.afterLast(ret) 
    178        return ret 
    179      
    180    def save(self, startTransaction=0, allRows=0, topLevel=1): 
    181        """ Saves any changes that have been made to the cursor. 
    182        If the save is successful, calls the save() of all child bizobjs. """ 
    183        self._errorMsg = "" 
    184          
    185        if not self.beforeSave() or not self.validate(): 
    186            return k.FILE_CANCEL 
    187  
    188        # See if we are saving a newly added record, or mods to an existing record. 
    189        isAdding = self._cursor.isAdding() 
    190          
    191        if startTransaction: 
    192            # Tell the cursor to issue a BEGIN TRANSACTION command 
    193            ret = self._cursor.beginTransaction() 
    194            if not ret == k.FILE_OK: 
    195                self.addToErrorMsg(self._cursor.getErrorMsg()) 
    196                return ret 
    197          
    198        # OK, this actually does the saving to the database 
    199        ret = self._cursor.save(allRows) 
    200          
    201        if ret == k.FILE_OK: 
    202            if isAdding: 
    203                # Call the hook method for saving new records. 
    204                self.onSaveNew() 
    205          
    206            # Iterate through the child bizobjs, telling them to save themselves. 
    207            for child in self.__children: 
    208                if child.isChanged(): 
    209                    # No need to start another transaction. And since this is a child bizobj,  
    210                    # we need to save all rows that have changed. 
    211                    ret = child.save(startTransaction=1, allRows=1, topLevel=0) 
    212                      
    213                    if not ret == k.FILE_OK: 
    214                        self.addToErrorMsg(child.getErrorMsg()) 
    215                        break 
    216  
    217        # Finish the transaction, and requery the children if needed. 
    218        if ret == k.FILE_OK: 
    219            if startTransaction: 
    220                self._cursor.commitTransaction() 
    221            if topLevel and self.requeryChildOnSave: 
    222                self.requeryAllChildren() 
    223              
    224            self.setMemento() 
    225              
    226        else: 
    227            # Something failed; reset things. 
    228            if startTransaction: 
    229                self._cursor.rollbackTransaction() 
    230            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    231  
    232        # Two hook methods: one specific to Save(), and one which is called after any change 
    233        # to the data (either save() or delete()). 
    234        self.afterChange(ret) 
    235        self.afterSave(ret) 
    236          
    237        return ret 
    238  
    239  
    240    def cancel(self, allRows=0): 
    241        """ Cancels any changes to the data. Reverts back to the orginal values 
    242        that were in the data. """ 
    243        self._errorMsg = "" 
    244          
    245        if not self.beforeCancel(): 
    246            return k.FILE_CANCEL 
    247          
    248        # Tell the cursor to cancel any changes 
    249        ret = self._cursor.cancel(allRows) 
    250          
    251        if ret == k.FILE_OK: 
    252            # Tell each child to cancel themselves 
    253            for child in self.__children: 
    254                ret = child.cancel(allRows) 
    255                if not ret == k.FILE_OK: 
    256                    self.addToErrorMsg(child.getErrorMsg()) 
    257                    break 
    258                ret = child.requery() 
    259          
    260        if ret == k.FILE_OK: 
    261            self.setMemento() 
    262        else: 
    263            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    264          
    265        self.afterCancel(ret) 
    266        return ret 
    267  
    268  
    269    def delete(self): 
    270        """ Deletes the current row of data """ 
    271        self._errorMsg = "" 
    272          
    273        if not self.beforeDelete() or not self.beforePointerMove(): 
    274            return k.FILE_CANCEL 
    275          
    276        if self.deleteChildLogic == k.REFINTEG_RESTRICT: 
    277            # See if there are any child records 
    278            for child in self.__children: 
    279                if child.getRowCount() > 0: 
    280                    self.addToErrorMsg("Deletion prohibited - there are related child records.") 
    281                    return k.FILE_CANCEL                    
    282          
    283        ret = self._cursor.delete() 
    284  
    285        if ret == k.FILE_OK: 
    286            if self._cursor.getRowCount() == 0: 
    287                # Hook method for handling the deletion of the last record in the cursor. 
    288                self.onDeleteLastRecord() 
    289            # Now cycle through any child bizobjs and fire their cancel() methods. This will 
    290            # ensure that any changed data they may have is reverted. They are then requeried to 
    291            # populate them with data for the current record in this bizobj. 
    292            for child in self.__children: 
    293                if self.deleteChildLogic == k.REFINTEG_CASCADE: 
    294                    child.deleteAll() 
    295                else: 
    296                    child.cancel(allRows=1) 
    297                    child.requery() 
    298              
    299            self.setMemento() 
    300        else: 
    301            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    302  
    303        self.afterPointerMove(ret) 
    304        self.afterChange(ret) 
    305        self.afterDelete(ret) 
    306        return ret 
    307          
    308      
    309    def deleteAll(self): 
    310        """ Iterate through all the rows in the bizobj's cursor, deleting each one-by-one""" 
    311        while self._cursor.getRowCount() > 0: 
    312            self.first() 
    313            ret = self.delete() 
    314            if ret != k.FILE_OK: 
    315                break 
    316        return ret 
    317  
    318  
    319    def new(self): 
    320        """ Creates a new record, and populates it with any default values specified. """ 
    321        self._errorMsg = "" 
    322          
    323        if not self.beforeNew() or not self.beforePointerMove(): 
    324            return k.FILE_CANCEL 
    325              
    326        ret = self._cursor.new() 
    327          
    328        if ret == k.FILE_OK: 
    329            # Hook method for things to do after a new record is created. 
    330            self.onNew() 
    331              
    332            # Update all child bizobjs 
    333            self.requeryAllChildren() 
    334              
    335            if self.newChildOnNew: 
    336                # Add records to all children set to have records created on a new parent record. 
    337                for child in self.__children: 
    338                    if child.newRecordOnNewParent: 
    339                        child.new() 
    340              
    341            self.setMemento() 
    342        else: 
    343            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    344          
    345        self.afterPointerMove(ret) 
    346        self.afterNew(ret) 
    347        return ret 
    348  
    349      
    350    def requery(self): 
    351        """ Refreshes the cursor's dataset with the current values in the database,  
    352        given the current state of the filtering parameters """ 
    353        self._errorMsg = "" 
    354          
    355        if not self.beforeRequery(): 
    356            return k.FILE_CANCEL 
    357          
    358        # Hook method for creating the param list 
    359        params = self.getParams() 
    360          
    361        # Record this in case we need to restore the record position 
    362        currPK = self.getPK() 
    363          
    364        # run the requery 
    365        ret = self._cursor.requery(params) 
    366          
    367        if ret == k.REQUERY_SUCCESS: 
    368            if self.savePosOnRequery: 
    369                self._cursor.moveToPK(currPK) 
    370              
    371            ret = self.requeryAllChildren() 
    372          
    373            self.setMemento() 
    374        else: 
    375            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    376          
    377        self.afterRequery(ret) 
    378        return ret 
    379      
    380      
    381    def setParams(self, params): 
    382        """ accepts a tuple that will be merged with the sql statement using the '%' 
    383        string format function. """ 
     6class dBizobj(object): 
     7    # Title of the cursor. Used in resolving DataSource references 
     8    dataSource = "" 
     9    # SQL statement used to create the cursor's data 
     10    sql = "" 
     11    # When true, the cursor object does not run its query immediately. Thi
     12    # is useful for parameterized queries 
     13    noDataOnLoad = 0 
     14    # Holds the params to be merged with the sql in the cursor 
     15    _params = () 
     16    # Reference to the cursor object  
     17    _cursor = None 
     18    # Reference to the parent bizobj to this one. 
     19    _parent = None 
     20    # Collection of child bizobjs for this 
     21    __children = [] 
     22    # Name of field that is the PK  
     23    keyField = "" 
     24    # Name of field that is the FK back to the paren
     25    linkField = "" 
     26    # Holds any error messages generated during a process 
     27    _errorMsg = "" 
     28    # Dictionary holding any default values to apply when a new record is created 
     29    defaultValues = {}       
     30    # Do we requery child bizobjs after a Save()? 
     31    requeryChildOnSave = 1 
     32    # Should new child records be added when a new parent record is added? 
     33    newChildOnNew = 0 
     34    # If this bizobj's parent has newChildOnNew =1, do we create a record here? 
     35    newRecordOnNewParent = 0 
     36    # In the onNew() method, do we fill in the linkField with the value returned by calling the parent 
     37    # bizobj's GetKeyValue() method? 
     38    fillLinkFromParent = 0 
     39    # After a requery, do we try to restore the record position to the same PK? 
     40    savePosOnRequery = 1 
     41 
     42    ########################################## 
     43    ### referential integrity stuff #### 
     44    ########################################## 
     45    ### Possible values for each type (not all are relevant for each action): 
     46    ### IGNORE - don't worry about the presence of child records 
     47    ### RESTRICT - don't allow action if there are child records 
     48    ### CASCADE - changes to the parent are cascaded to the children 
     49    deleteChildLogic = k.REFINTEG_CASCADE       # child records will be deleted 
     50    updateChildLogic = k.REFINTEG_IGNORE    # parent keys can be changed w/o affecting children 
     51    insertChildLogic = k.REFINTEG_IGNORE        # child records can be inserted even if no parent record exists. 
     52    ########################################## 
     53    # Versioning... 
     54    _version = "0.1.0" 
     55 
     56 
     57    def __init__(self, dConnection): 
     58        # Save the connection reference 
     59        self._conn = dConnection 
     60        # Mixin class 1 : the dabo cursor class 
     61        self.dCursorMixinClass = dCursorMixin 
     62        # Mixin class 2 : the cursor class from the db api 
     63        self.dbapiCursorClass = self._conn.getDictCursor() 
     64        self.createCursor() 
     65        # Need to set this so that different instances don't mix up the references 
     66        # contained in this list. 
     67        self.__children = [] 
     68     
     69         
     70    def createCursor(self):         
     71        # Create the cursor that this bizobj will be using for data 
     72        if self.beforeCreateCursor(): 
     73            cursorClass = self.getCursorClass(self.dCursorMixinClass, self.dbapiCursorClass) 
     74            self._cursor = self._conn.getConnection().cursor(cursorclass=cursorClass
     75            self._cursor.setSQL(self.sql
     76            self._cursor.setKeyField(self.keyField
     77            self._cursor.setTable(self.dataSource) 
     78            if not self.noDataOnLoad: 
     79                self._cursor.requery() 
     80            self.afterCreateCursor() 
     81 
     82        if not self._cursor: 
     83            ##### TODO  ####### 
     84            # Need to raise an exception here! 
     85            pass 
     86 
     87                     
     88    def getCursorClass(self, main, secondary): 
     89        class cursorMix(main, secondary): 
     90            superMixin = main 
     91            superCursor = secondary 
     92            def __init__(self, *args, **kwargs): 
     93                if hasattr(main, "__init__"): 
     94                    apply(main.__init__,(self,) + args, kwargs) 
     95                    #main.__init__(self) 
     96                if hasattr(secondary, "__init__"): 
     97                    apply(secondary.__init__,(self,) + args, kwargs) 
     98        return  cursorMix 
     99 
     100 
     101    def first(self): 
     102        """ Move the record pointer in the cursor to the first record of the  
     103            result set. Update any child bizobjs to reflect the new current  
     104            parent record. If the record set is already at the beginning,  
     105            return k.FILE_BOF.  
     106        """ 
     107        self._errorMsg = "" 
     108        if not self.beforeFirst() or not self.beforePointerMove(): 
     109            return k.FILE_CANCEL 
     110        ret = self._cursor.first() 
     111 
     112        if ret == k.FILE_OK: 
     113            self.requeryAllChildren() 
     114            self.setMemento() 
     115        else: 
     116            self.addToErrorMsg(self._cursor.getErrorMsg()
     117        self.afterPointerMove(ret) 
     118        self.afterFirst(ret
     119        return ret 
     120 
     121 
     122    def prior(self): 
     123        """ Move the record pointer in the cursor back one position in the  
     124            result set. Update any child bizobjs to reflect the new current  
     125            parent record. If the record set is already at the beginning,  
     126            return k.FILE_BOF.  
     127        """ 
     128        self._errorMsg = "" 
     129        if not self.beforePrior() or not self.beforePointerMove(): 
     130            return k.FILE_CANCEL 
     131        ret = self._cursor.prior() 
     132 
     133        if ret == k.FILE_OK: 
     134            self.requeryAllChildren() 
     135            self.setMemento() 
     136        else: 
     137            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     138        self.afterPointerMove(ret) 
     139        self.afterPrior(ret) 
     140        return ret 
     141 
     142 
     143    def next(self): 
     144        """ Moves the record pointer in the cursor to the next record of the result set. 
     145        Updates any child bizobjs to reflect the new current parent record. 
     146        If the recordset is already at the last record, returns k.FILE_EOF. """ 
     147        self._errorMsg = "" 
     148        if not self.beforeNext() or not self.beforePointerMove(): 
     149            return k.FILE_CANCEL 
     150        ret = self._cursor.next() 
     151 
     152        if ret == k.FILE_OK: 
     153            self.requeryAllChildren() 
     154            self.setMemento() 
     155        else: 
     156            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     157        self.afterPointerMove(ret) 
     158        self.afterNext(ret) 
     159        return ret 
     160 
     161 
     162    def last(self): 
     163        """ Moves the record pointer in the cursor to the last record of the result set. 
     164        Updates any child bizobjs to reflect the new current parent record. 
     165        If the recordset is already at the last record, returns k.FILE_EOF. """ 
     166        self._errorMsg = "" 
     167        if not self.beforeLast() or not self.beforePointerMove(): 
     168            return k.FILE_CANCEL 
     169        ret = self._cursor.last() 
     170 
     171        if ret == k.FILE_OK: 
     172            self.requeryAllChildren() 
     173            self.setMemento() 
     174        else: 
     175            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     176        self.afterPointerMove(ret) 
     177        self.afterLast(ret) 
     178        return ret 
     179 
     180    def save(self, startTransaction=0, allRows=0, topLevel=1): 
     181        """ Saves any changes that have been made to the cursor. 
     182        If the save is successful, calls the save() of all child bizobjs. """ 
     183        self._errorMsg = "" 
     184 
     185        if not self.beforeSave() or not self.validate(): 
     186            return k.FILE_CANCEL 
     187 
     188        # See if we are saving a newly added record, or mods to an existing record. 
     189        isAdding = self._cursor.isAdding() 
     190 
     191        if startTransaction: 
     192            # Tell the cursor to issue a BEGIN TRANSACTION command 
     193            ret = self._cursor.beginTransaction() 
     194            if not ret == k.FILE_OK: 
     195                self.addToErrorMsg(self._cursor.getErrorMsg()) 
     196                return ret 
     197 
     198        # OK, this actually does the saving to the database 
     199        ret = self._cursor.save(allRows) 
     200 
     201        if ret == k.FILE_OK: 
     202            if isAdding: 
     203                # Call the hook method for saving new records. 
     204                self.onSaveNew() 
     205 
     206            # Iterate through the child bizobjs, telling them to save themselves. 
     207            for child in self.__children: 
     208                if child.isChanged(): 
     209                    # No need to start another transaction. And since this is a child bizobj,  
     210                    # we need to save all rows that have changed. 
     211                    ret = child.save(startTransaction=1, allRows=1, topLevel=0) 
     212 
     213                    if not ret == k.FILE_OK: 
     214                        self.addToErrorMsg(child.getErrorMsg()) 
     215                        break 
     216 
     217        # Finish the transaction, and requery the children if needed. 
     218        if ret == k.FILE_OK: 
     219            if startTransaction: 
     220                self._cursor.commitTransaction() 
     221            if topLevel and self.requeryChildOnSave: 
     222                self.requeryAllChildren() 
     223 
     224            self.setMemento() 
     225 
     226        else: 
     227            # Something failed; reset things. 
     228            if startTransaction: 
     229                self._cursor.rollbackTransaction() 
     230            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     231 
     232        # Two hook methods: one specific to Save(), and one which is called after any change 
     233        # to the data (either save() or delete()). 
     234        self.afterChange(ret) 
     235        self.afterSave(ret) 
     236 
     237        return ret 
     238 
     239 
     240    def cancel(self, allRows=0): 
     241        """ Cancels any changes to the data. Reverts back to the orginal values 
     242        that were in the data. """ 
     243        self._errorMsg = "" 
     244 
     245        if not self.beforeCancel(): 
     246            return k.FILE_CANCEL 
     247 
     248        # Tell the cursor to cancel any changes 
     249        ret = self._cursor.cancel(allRows) 
     250 
     251        if ret == k.FILE_OK: 
     252            # Tell each child to cancel themselves 
     253            for child in self.__children: 
     254                ret = child.cancel(allRows) 
     255                if not ret == k.FILE_OK: 
     256                    self.addToErrorMsg(child.getErrorMsg()) 
     257                    break 
     258                ret = child.requery() 
     259 
     260        if ret == k.FILE_OK: 
     261            self.setMemento() 
     262        else: 
     263            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     264 
     265        self.afterCancel(ret) 
     266        return ret 
     267 
     268 
     269    def delete(self): 
     270        """ Deletes the current row of data """ 
     271        self._errorMsg = "" 
     272 
     273        if not self.beforeDelete() or not self.beforePointerMove(): 
     274            return k.FILE_CANCEL 
     275 
     276        if self.deleteChildLogic == k.REFINTEG_RESTRICT: 
     277            # See if there are any child records 
     278            for child in self.__children: 
     279                if child.getRowCount() > 0: 
     280                    self.addToErrorMsg("Deletion prohibited - there are related child records.") 
     281                    return k.FILE_CANCEL                   
     282 
     283        ret = self._cursor.delete() 
     284 
     285        if ret == k.FILE_OK: 
     286            if self._cursor.getRowCount() == 0: 
     287                # Hook method for handling the deletion of the last record in the cursor. 
     288                self.onDeleteLastRecord() 
     289            # Now cycle through any child bizobjs and fire their cancel() methods. This will 
     290            # ensure that any changed data they may have is reverted. They are then requeried to 
     291            # populate them with data for the current record in this bizobj. 
     292            for child in self.__children: 
     293                if self.deleteChildLogic == k.REFINTEG_CASCADE: 
     294                    child.deleteAll() 
     295                else: 
     296                    child.cancel(allRows=1) 
     297                    child.requery() 
     298 
     299            self.setMemento() 
     300        else: 
     301            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     302 
     303        self.afterPointerMove(ret) 
     304        self.afterChange(ret) 
     305        self.afterDelete(ret) 
     306        return ret 
     307 
     308 
     309    def deleteAll(self): 
     310        """ Iterate through all the rows in the bizobj's cursor, deleting each one-by-one""" 
     311        while self._cursor.getRowCount() > 0: 
     312            self.first() 
     313            ret = self.delete() 
     314            if ret != k.FILE_OK: 
     315                break 
     316        return ret 
     317 
     318 
     319    def new(self): 
     320        """ Creates a new record, and populates it with any default values specified. """ 
     321        self._errorMsg = "" 
     322 
     323        if not self.beforeNew() or not self.beforePointerMove(): 
     324            return k.FILE_CANCEL 
     325 
     326        ret = self._cursor.new() 
     327 
     328        if ret == k.FILE_OK: 
     329            # Hook method for things to do after a new record is created. 
     330            self.onNew() 
     331 
     332            # Update all child bizobjs 
     333            self.requeryAllChildren() 
     334 
     335            if self.newChildOnNew: 
     336                # Add records to all children set to have records created on a new parent record. 
     337                for child in self.__children: 
     338                    if child.newRecordOnNewParent: 
     339                        child.new() 
     340 
     341            self.setMemento() 
     342        else: 
     343            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     344 
     345        self.afterPointerMove(ret) 
     346        self.afterNew(ret) 
     347        return ret 
     348 
     349 
     350    def requery(self): 
     351        """ Refreshes the cursor's dataset with the current values in the database,  
     352        given the current state of the filtering parameters """ 
     353        self._errorMsg = "" 
     354 
     355        if not self.beforeRequery(): 
     356            return k.FILE_CANCEL 
     357 
     358        # Hook method for creating the param list 
     359        params = self.getParams() 
     360 
     361        # Record this in case we need to restore the record position 
     362        currPK = self.getPK() 
     363 
     364        # run the requery 
     365        ret = self._cursor.requery(params) 
     366 
     367        if ret == k.REQUERY_SUCCESS: 
     368            if self.savePosOnRequery: 
     369                self._cursor.moveToPK(currPK) 
     370 
     371            ret = self.requeryAllChildren() 
     372 
     373            self.setMemento() 
     374        else: 
     375            self.addToErrorMsg(self._cursor.getErrorMsg()) 
     376 
     377        self.afterRequery(ret) 
     378        return ret 
     379 
     380 
     381    def setParams(self, params): 
     382        """ accepts a tuple that will be merged with the sql statement using the '%' 
     383        string format function. """ 
    384384#       if params != types.TupleType: 
    385385#           params = tuple(params) 
    386        self._params = params 
    387      
    388      
    389    def validate(self): 
    390        """ This is the method that you should customize in your subclasses 
    391        to create checks on the data entered by the user to be sure that it  
    392        conforms to your business rules.  
    393          
    394        It is called by the Save() routine before saving any data. If this returns 
    395        a false value, the save will be disallowed. You must return a True value  
    396        for data saving to proceed. """ 
    397        return 1 
    398          
    399          
    400    def isChanged(self): 
    401        """ Returns whether or not the data for the current record in the cursor has changed, or 
    402        if the data in any child bizobjs has changed. """ 
    403        ret = self._cursor.isChanged() 
    404          
    405        if not ret: 
    406            # see if any child bizobjs have changed 
    407            for child in self.__children: 
    408                ret = ret and child.isChanged() 
    409          
    410        return ret 
    411      
    412      
    413    def onDeleteLastRecord(self): 
    414        """ Hook method called when the last record of the cursor has been deleted """ 
    415        pass 
    416      
    417      
    418    def onNew(self): 
    419        """ Populates the record with any default values """ 
    420        self._cursor.setDefaults(self.defaultValues) 
    421          
    422        # Call the custom hook method 
    423        self.onNewHook() 
    424      
    425      
    426    def onNewHook(self): 
    427        """ Hook method called after the default values have been set in onNew(). """ 
    428        pass 
    429      
    430      
    431    def addChild(self, child): 
    432        """ During the creation of the form, child bizobjs are added by the parent. 
    433        This stores the child reference here, and sets the reference to the parent in the child. """ 
    434        if child not in self.__children: 
    435            self.__children.append(child) 
    436            child.setParent(self) 
    437      
    438      
    439    def setParent(self, parent): 
    440        """ Stores a reference to this object's parent bizobj. """ 
    441        self._parent = parent 
    442      
    443      
    444    def requeryAllChildren(self): 
    445        """ Called to assure that all child bizobjs have had their data sets refreshed to  
    446        match the current status. """ 
    447        if len(self.__children) == 0: 
    448            return k.REQUERY_SUCCESS 
    449        if self.beforeChildRequery(): 
    450            ret = k.REQUERY_SUCCESS 
    451            for child in self.__children: 
    452                ret = child.requery() 
    453                if not ret == k.REQUERY_SUCCESS: 
    454                    break 
    455        else: 
    456            # Something prevented the child requerying  
    457            ret = k.REQUERY_ERROR 
    458          
    459        if ret != k.REQUERY_SUCCESS: 
    460            self.addToErrorMsg(self._cursor.getErrorMsg()) 
    461              
    462        self.afterChildRequery(ret) 
    463        return ret 
    464      
    465      
    466    def getPK(self): 
    467        """ Returns the value of the PK field """ 
    468        return self._cursor.getFieldVal(self.keyField) 
    469  
    470  
    471    def getParentPK(self): 
    472        """ Returns the value of the parent bizobjs' PK. """ 
    473        if self._parent is not None: 
    474            return self._parent.getPK() 
    475        else: 
    476            return None 
    477  
    478          
    479    def getFieldVal(self, fld): 
    480        """ Returns the value of the requested field """ 
    481        return self._cursor.getFieldVal(fld) 
    482          
    483          
    484    def setFieldVal(self, fld, val): 
    485        """ Sets the value of the specified field """ 
    486        return self._cursor.setFieldVal(fld, val) 
    487          
    488          
    489    def getParams(self): 
    490        """ This is the place to define the parameters to be used to modify 
    491        the SQL statement used to produce the record set. If the cursor for 
    492        this bizobj does not need parameters, leave this as is. Otherwise,  
    493        use this method to create a tuple to be passed to the cursor, where  
    494        it will be used to modify the query using standard printf syntax. """ 
    495        return self._params 
    496      
    497      
    498    def setMemento(self): 
    499        """ Tell the cursor to take a snapshot of the current state of the  
    500        data. This snapshot will be used to determine what, if anything, has  
    501        changed later on. """ 
    502        self._cursor.setMemento() 
    503  
    504  
    505    def getRowCount(self): 
    506        """ Returns the number of records in the cursor's data set.""" 
    507        return self._cursor.getRowCount() 
    508      
    509      
    510    def addToErrorMsg(self, txt): 
    511        """ Adds the passed text to the current error message text,  
    512        inserting a newline if needed """ 
    513        if txt: 
    514            if self._errorMsg: 
    515                self._errorMsg += "\n" 
    516            self._errorMsg += txt 
    517  
    518    def getErrorMsg(self): 
    519        return self._errorMsg 
    520  
    521          
    522    ########## Pre-hook interface section ############## 
    523    def beforeNew(self): return 1 
    524    def beforeDelete(self): return 1 
    525    def beforeFirst(self): return 1 
    526    def beforePrior(self): return 1 
    527    def beforeNext(self): return 1 
    528    def beforeLast(self): return 1 
    529    def beforePointerMove(self): return 1 
    530    def beforeSave(self): return 1 
    531    def beforeCancel(self): return 1 
    532    def beforeRequery(self): return 1 
    533    def beforeChildRequery(self): return 1 
    534    def beforeConnection(self): return 1 
    535    def beforeCreateCursor(self): return 1 
    536    ########## Post-hook interface section ############## 
    537    def afterNew(self, retStatus): pass 
    538    def afterDelete(self, retStatus): pass 
    539    def afterFirst(self, retStatus): pass 
    540    def afterPrior(self, retStatus): pass 
    541    def afterNext(self, retStatus): pass 
    542    def afterLast(self, retStatus): pass 
    543    def afterPointerMove(self, retStatus): pass 
    544    def afterSave(self, retStatus): pass 
    545    def afterCancel(self, retStatus): pass 
    546    def afterRequery(self, retStatus): pass 
    547    def afterChildRequery(self, retStatus): pass 
    548    def afterChange(self, retStatus): pass 
    549    def afterConnection(self): pass 
    550    def afterCreateCursor(self): pass 
    551  
     386        self._params = params 
     387 
     388 
     389    def validate(self): 
     390        """ This is the method that you should customize in your subclasses 
     391        to create checks on the data entered by the user to be sure that it  
     392        conforms to your business rules.  
     393 
     394        It is called by the Save() routine before saving any data. If this returns 
     395        a false value, the save will be disallowed. You must return a True value  
     396        for data saving to proceed. """ 
     397        return 1 
     398 
     399 
     400    def isChanged(self): 
     401        """ Returns whether or not the data for the current record in the cursor has changed, or 
     402        if the data in any child bizobjs has changed. """ 
     403        ret = self._cursor.isChanged() 
     404 
     405        if not ret: 
     406            # see if any child bizobjs have changed 
     407            for child in self.__children: 
     408                ret = ret and child.isChanged() 
     409 
     410        return ret 
     411 
     412 
     413    def onDeleteLastRecord(self): 
     414        """ Hook method called when the last record of the cursor has been deleted """ 
     415        pass 
     416 
     417 
     418    def onNew(self): 
     419        """ Populates the record with any default values """ 
     420        self._cursor.setDefaults(self.defaultValues) 
     421 
     422        # Call the custom hook method 
     423        self.onNewHook() 
     424 
     425 
     426    def onNewHook(self): 
     427        """ Hook method called after the default values have been set in onNew(). """ 
     428        pass 
     429 
     430 
     431    def addChild(self, child): 
     432        """ During the creation of the form, child bizobjs are added by the parent. 
     433        This stores the child reference here, and sets the reference to the parent in the child. """ 
     434        if child not in self.__children: 
     435            self.__children.append(child) 
     436            child.setParent(self) 
     437 
     438 
     439    def setParent(self, parent): 
     440        """ Stores a reference to this object's parent bizobj. """ 
     441        self._parent = parent 
     442 
     443 
     444    def requeryAllChildren(self): 
     445        """ Called to assure that all child bizobjs have had their data sets refreshed to  
     446        match the current status. """ 
     447        if len(self.__children) == 0: 
     448            return k.REQUERY_SUCCESS 
     449        if self.beforeChildRequery(): 
     450            ret = k.REQUERY_SUCCESS 
     451            for child in self.__children: 
     452            &n