Changeset 3119

Show
Ignore:
Timestamp:
05/10/07 09:06:47 (1 year ago)
Author:
nate
Message:

updated my branch and fixed conflicts in preperation for merge to trunk.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/NateBranch/AUTHORS

    r2715 r3119  
    1818 
    1919Thanks everyone for using, improving, and enjoying Dabo!! 
     20 
  • branches/NateBranch/ChangeLog

    r3009 r3119  
    22 
    33=============================================================================== 
    4 Dabo 0.8 (2007-04-01) (Revision 3010): 
     4Dabo 0.8 (2007-05-09) (Revision 3111): 
    55 
    66Enhancements: 
    77 
    88    ===== General Stuff ===== 
     9+ Improved a lot of the handling of paths. It is now possible to correctly  
     10  resolve a relative path when the source file and the contained file are in  
     11  different directories, while the app is running from a third directory. 
     12 
    913+ Added datanav2; deprecated datanav. datanav2 no longer supports fieldSpecs, 
    1014  relationSpecs, and other things. The general theme is that the generated 
     
    2327 
    2428    ===== UI Tier ===== 
     29+ Began work getting grid cell properties set up. IOW, being able to set the 
     30  ForeColor of a specific row in a column (a single cell), including 
     31  dynamic cell properties. Currently, it works, but the only property 
     32  I've added yet is CellForeColor and DynamicCellForeColor. 
     33 
     34+ Removed the requirement that objects used as DataSources have to inherit  
     35  from dObject. Thanks Carl for pointing out the limitation. 
     36 
     37+ Added dDockForm to the main trunk, which is Dabo's wrapper for wxAUI.  
     38 
     39+ Added the option of passing complex filter expressions to setAll(). This  
     40  function now accepts a tuple of filter expressions of the format  
     41  'att comp val', which will be eval'd with the child objects inn order to  
     42  determine if the filter applies. Each expression in the tuple is ANDed  
     43  with the others; all the tuple elements must evaluate to True for the  
     44  value to be set. 
     45 
     46+ Added the dHtmlBox.HtmlLinkClicked event. 
     47 
     48+ Added the HatchStyle property to draw objects. This gives you the option  
     49  of specifying that the fill for drawn objects can be one of the following  
     50  hatch patterns: 
     51 
     52    Solid (default) 
     53    Transparent 
     54    Cross 
     55    Horizontal 
     56    Vertical 
     57    Diagonal 
     58    ReverseDiagonal 
     59    CrossDiagonal 
     60 
    2561+ EasyDialogBuilder - minor improvements by Nate Lowrie. 
    2662 
     
    6399+ Added AutoAutoCompletion option to dEditor. 
    64100 
     101+ Added methods to dabo.ui: isMouseLeftDown(), isMouseRightDown(),  
     102  and isMouseMiddleDown(). 
     103 
     104+ Added tango icon theme and changed our toolbars/menus to reference the new 
     105  icons. (Ticket # 1037) 
     106 
     107+ Added Modal property to dForm, settable only by sending the property to the 
     108  constructor. When Modal, a dialog instead of a form will be instantiated. 
     109 
     110+ dEditor now properly syntax-colors dabo-based xml files such as .cdxml 
     111  and .rfxml. Previously, it displayed these files using Python coloring. 
     112 
     113+ Removed IconBundle property from dFormMixin. Added the ability to set Form.Icon 
     114  to a sequence of filenames which Dabo will convert to a wx.IconBundle 
     115  automatically. 
     116 
     117+ Added property WordWrap to dEditBox. Default is True. 
     118 
    65119    ===== Data Tier ===== 
     120+ Added the option of passing additional keyword arguments to db.dConnection. 
     121  Thanks Uwe for noting the limitation. 
     122 
    66123+ dbFirebird - Minor improvements by Uwe Grauer. 
    67124 
     
    84141  flexible interface to reference calculated fields on the fly. 
    85142 
     143+ Added the 'SaveNewUnchanged' property to dBizobj. When this is True, new  
     144  records that have not been modified from their defaults are saved; the  
     145  default remains to not insert such records.  
     146 
    86147+ Improved data binding to bizobjs on a parent form. 
    87148 
     
    123184 
    124185+ Fixed rapid flashing in a sorted dGrid when an editable column was selected. 
     186 
     187+ Fixed bug that prevented adding new records when child bizobjs existed. 
     188  (Ticket #1027). Thanks to Larry Long and John Fabiani for continued 
     189  assistance in tracking these problems down. 
     190 
     191+ setWhereClause() method missing in dBizobj. Fixed. 
     192 
     193+ Fixed dCursor.getChangedRows() to not take into account new records that 
     194  have no changes. 
     195 
     196+ Fixed the dBizobj.save() process to not scan all child bizobj's repeatedly. 
     197  This fixes some problems, and speeds up save() considerably. 
     198 
     199+ Fixed a problem where canceling a bizobj that had no records caused an  
     200  exception that was being displayed with notifyUser(). Normally, a bizobj  
     201  with no records does not need canceling, so raising such an error is not  
     202  appropriate. You can still have the old behavior by calling cancel() with  
     203  'ignoreNoRecords = False'. 
     204 
     205+ Fixed a bug reported by Larry Long and John Fabiani that involved requerying 
     206  one bizobj resulted in checking for pending changes in other bizobjs that  
     207  were not involved in the requery. 
     208 
     209+ Descending sorts created infinite loop with duplicate values. Fixed. 
     210  (Ticket #1041). Thanks Jussi. 
     211 
     212+ Fixed status text to clear the old field validation failed message when the 
     213  user fixes the value and the field now passes validation. 
     214 
     215+ Fixed the geometry persistence to only restore the size of the form from  
     216  user settings if BorderResizable is set to True.  
     217 
     218+ Fixed dGrid's AlternateRowColoring to be settable from the constructor 
     219  or initProperties (previously, it was only settable in afterInit() or 
     220  later).  
     221 
     222+ Dynamic props on dColumn were not working: fixed. 
     223 
     224+ Fixed a bug that confused the string 'None' with the null value None when  
     225  setting BorderStyle from a cdxml. Thanks to Miguel for catching this one. 
     226 
     227+ Fixed a couple of bugs related to the dSizer.BorderSides property.  
     228  Previously it was not retrieving that property correctly from the internal  
     229  wx flag. 
    125230 
    126231 
  • branches/NateBranch/dabo/__init__.py

    r2810 r3119  
     1# -*- coding: utf-8 -*- 
    12""" Dabo: A Framework for developing data-driven business applications 
    23 
  • branches/NateBranch/dabo/__version__.py

    r3017 r3119  
     1# -*- coding: utf-8 -*- 
    12# The following 2 lines are the only thing you should change in this file. 
    23# Everything else is boilerplate copied also to other dabo repositories. 
    34package_name = "dabo" 
    4 _version = "0.8a" 
     5_version = "0.9a" 
    56 
    67 
  • branches/NateBranch/dabo/biz/__init__.py

    r2054 r3119  
     1# -*- coding: utf-8 -*- 
    12""" dabo.biz : Dabo Business Objects (bizobjs) 
    23 
  • branches/NateBranch/dabo/biz/dAutoBizobj.py

    r2727 r3119  
     1# -*- coding: utf-8 -*- 
    12import datetime 
    23import dabo 
  • branches/NateBranch/dabo/biz/dBizobj.py

    r3038 r3119  
     1# -*- coding: utf-8 -*- 
    12import types 
    23import re 
     
    1718 
    1819 
    19     def __init__(self, conn, properties=None, *args, **kwargs): 
     20    def __init__(self, conn=None, properties=None, *args, **kwargs): 
    2021        """ User code should override beforeInit() and/or afterInit() instead.""" 
    2122        self.__att_try_setFieldVal = False 
     
    3132 
    3233        self._beforeInit() 
    33         cf = self._cursorFactory = conn 
    34         if cf: 
    35             # Base cursor class : the cursor class from the db api 
    36             self.dbapiCursorClass = cf.getDictCursorClass() 
    37  
    38             # If there are any problems in the createCursor process, an 
    39             # exception will be raised in that method. 
    40             self.createCursor() 
    41  
     34        self.setConnection(conn) 
    4235        # We need to make sure the cursor is created *before* the call to 
    4336        # initProperties() 
     
    5649        self._baseClass = dBizobj 
    5750        self.__areThereAnyChanges = False   # Used by the isChanged() method. 
    58         # Next two are used by the scan() method. 
    59         self.__scanRestorePosition = True 
    60         self.__scanReverse = False 
    6151        # Used by the LinkField property 
    6252        self._linkField = "" 
     
    7060        self._caption = "" 
    7161        self._dataSource = "" 
     62        self._scanRestorePosition = None 
    7263        self._SQL = "" 
    7364        self._requeryOnLoad = False 
     
    9788 
    9889        self.beforeInit() 
     90 
     91 
     92    def setConnection(self, conn): 
     93        """Normally connections are established before bizobj creation, but  
     94        for those cases where connections are created later, use this method to  
     95        establish the connection used by the bizobj. 
     96        """ 
     97        self._cursorFactory = conn 
     98        if conn: 
     99            # Base cursor class : the cursor class from the db api 
     100            self.dbapiCursorClass = self._cursorFactory.getDictCursorClass() 
     101            # If there are any problems in the createCursor process, an 
     102            # exception will be raised in that method. 
     103            self.createCursor() 
    99104 
    100105 
     
    262267            cursor.beginTransaction() 
    263268         
    264         changed_rows = self.getChangedRows() 
    265         for row in changed_rows: 
    266             self._moveToRowNum(row) 
    267             try: 
    268                 self.save(startTransaction=False, topLevel=False) 
    269             except dException.ConnectionLostException, e: 
    270                 self.RowNumber = current_row 
    271                 raise dException.ConnectionLostException, e 
    272             except dException.DBQueryException, e: 
    273                 # Something failed; reset things. 
    274                 if useTransact: 
    275                     cursor.rollbackTransaction() 
    276                 # Pass the exception to the UI 
    277                 self.RowNumber = current_row 
    278                 raise dException.DBQueryException, e 
    279             except dException.dException, e: 
    280                 if useTransact: 
    281                     cursor.rollbackTransaction() 
    282                 self.RowNumber = current_row 
    283                 raise 
     269        try: 
     270            self.scanChangedRows(self.save, includeNewUnchanged=self.SaveNewUnchanged, 
     271                    startTransaction=False, topLevel=False) 
     272        except dException.ConnectionLostException, e: 
     273            self.RowNumber = current_row 
     274            raise dException.ConnectionLostException, e 
     275        except dException.DBQueryException, e: 
     276            # Something failed; reset things. 
     277            if useTransact: 
     278                cursor.rollbackTransaction() 
     279            # Pass the exception to the UI 
     280            self.RowNumber = current_row 
     281            raise dException.DBQueryException, e 
     282        except dException.dException, e: 
     283            if useTransact: 
     284                cursor.rollbackTransaction() 
     285            self.RowNumber = current_row 
     286            raise 
    284287 
    285288        if useTransact: 
     
    368371 
    369372    def cancelAll(self, ignoreNoRecords=None): 
    370         """Cancel all changes made to the current dataset, including all children.""" 
    371         self.scanChangedRows(self.cancel, allCursors=False, ignoreNoRecords=ignoreNoRecords) 
     373        """Cancel all changes made to the current dataset, including all children 
     374        and all new, unmodified records. 
     375        """ 
     376        self.scanChangedRows(self.cancel, allCursors=False, includeNewUnchanged=True, 
     377                ignoreNoRecords=ignoreNoRecords) 
    372378 
    373379 
     
    386392            # normally not be a problem. 
    387393            ignoreNoRecords = True 
    388  
    389394        # Tell the cursor and all children to cancel themselves: 
    390395        self._CurrentCursor.cancel(ignoreNoRecords=ignoreNoRecords) 
    391396        for child in self.__children: 
    392397            child.cancelAll(ignoreNoRecords=ignoreNoRecords) 
    393  
    394398        self.afterCancel() 
    395399         
     
    501505 
    502506 
    503     def getChangedRows(self): 
    504         """ Returns a list of row numbers for which isChanged()    returns True. The  
     507    def getChangedRows(self, includeNewUnchanged=False): 
     508        """ Returns a list of row numbers for which isChanged() returns True. The  
    505509        changes may therefore not be in the record itself, but in a dependent child  
    506         record. 
     510        record. If includeNewUnchanged is True, the presence of a new unsaved 
     511        record that has not been modified from its defaults will suffice to mark the 
     512        record as changed. 
    507513        """ 
    508514        if self.__children: 
     
    513519        else: 
    514520            # Can use the much faster cursor.getChangedRows(): 
    515             return self._CurrentCursor.getChangedRows(
     521            return self._CurrentCursor.getChangedRows(includeNewUnchanged
    516522 
    517523 
     
    536542 
    537543 
    538     def scan(self, func, *args, **kwargs): 
     544    def scan(self, func, reverse=False, *args, **kwargs): 
    539545        """Iterate over all records and apply the passed function to each. 
    540546 
    541547        Set self.exitScan to True to exit the scan on the next iteration. 
    542548 
    543         If self.__scanRestorePosition is True, the position of the current 
    544         record in the recordset is restored after the iteration. If 
    545         self.__scanReverse is true, the records are processed in reverse order. 
    546         """ 
    547         self.scanRows(func, range(self.RowCount), *args, **kwargs) 
    548  
    549  
    550     def scanRows(self, func, rows, *args, **kwargs): 
     549        If self.ScanRestorePosition is True, the position of the current 
     550        record in the recordset is restored after the iteration. If the 'reverse' 
     551        parameter is True, the records are processed in reverse order. 
     552        """ 
     553        self.scanRows(func, range(self.RowCount), reverse=reverse, *args, **kwargs) 
     554 
     555 
     556    def scanRows(self, func, rows, reverse=False, *args, **kwargs): 
    551557        """Iterate over the specified rows and apply the passed function to each. 
    552558 
     
    556562        self.exitScan = False 
    557563        rows = list(rows) 
    558         if self.__scanRestorePosition: 
     564        if self.ScanRestorePosition: 
    559565            try: 
    560566                currPK = self.getPK() 
     
    565571                currRow = self.RowNumber 
    566572        try: 
    567             if self.__scanReverse: 
     573            if reverse: 
    568574                rows.reverse() 
    569575            for i in rows: 
     
    573579                    break 
    574580        except dException.dException, e: 
    575             if self.__scanRestorePosition: 
     581            if self.ScanRestorePosition: 
    576582                self.RowNumber = currRow 
    577583            raise dException.dException, e 
    578584 
    579         if self.__scanRestorePosition: 
     585        if self.ScanRestorePosition: 
    580586            if currPK is not None: 
    581587                self._positionUsingPK(currPK, updateChildren=False) 
     
    591597         
    592598 
    593     def scanChangedRows(self, func, allCursors=False, *args, **kwargs): 
     599    def scanChangedRows(self, func, allCursors=False, includeNewUnchanged=False, 
     600            *args, **kwargs): 
    594601        """Move the record pointer to each changed row, and call func. 
    595602 
    596603        If allCursors is True, all other cursors for different parent records will  
    597         be iterated as well.  
     604        be iterated as well. 
     605         
     606        If includeNewUnchanged is True, new unsaved records that have not been 
     607        edited from their default values will be counted as 'changed'. 
    598608 
    599609        If you want to end the scan on the next iteration, set self.exitScan=True. 
     
    603613        """ 
    604614        self.exitScan = False 
     615        currCursor = self._CurrentCursor 
    605616        old_currentCursorKey = self.__currentCursorKey 
    606617        try: 
    607             old_pk = self._CurrentCursor.getPK() 
     618            old_pk = currCursor.getPK() 
    608619        except dException.NoRecordsException: 
    609620            # no rows to scan 
     
    613624            cursors = self.__cursors 
    614625        else: 
    615             cursors = {old_pk: self._CurrentCursor} 
     626            cursors = {old_currentCursorKey: currCursor} 
    616627 
    617628        for key, cursor in cursors.iteritems(): 
    618629            self._CurrentCursor = key 
    619             changed_keys = list(set(cursor._mementos.keys() + cursor._newRecords.keys())
    620             for pk in changed_keys: 
    621                 self._positionUsingPK(pk
     630            changedRows = self.getChangedRows(includeNewUnchanged
     631            for row in changedRows: 
     632                self._moveToRowNum(row
    622633                try: 
    623634                    func(*args, **kwargs) 
     
    940951            return False 
    941952         
    942         if cc.isChanged(allRows=True): 
     953        if cc.isChanged(allRows=True, includeNewUnchanged=self.SaveNewUnchanged): 
    943954            return True 
    944955     
     
    970981            # No cursor, no changes. 
    971982            return False 
    972         ret = cc.isChanged(allRows=False
     983        ret = cc.isChanged(allRows=False, includeNewUnchanged=self.SaveNewUnchanged
    973984 
    974985        if not ret: 
     
    10551066            if val is None: 
    10561067                val = self.getParentPK() 
    1057             self.scan(self._setParentFK, val
     1068            self.scan(self._setParentFK, val=val
    10581069 
    10591070    def _setParentFK(self, val): 
     
    17171728 
    17181729 
     1730    def _getSaveNewUnchanged(self): 
     1731        try: 
     1732            ret = self._saveNewUnchanged 
     1733        except AttributeError: 
     1734            ret = self._saveNewUnchanged = False 
     1735        return ret 
     1736 
     1737    def _setSaveNewUnchanged(self, val): 
     1738        self._saveNewUnchanged = val 
     1739 
     1740 
     1741    def _getScanRestorePosition(self): 
     1742        return self._scanRestorePosition 
     1743 
     1744    def _setScanRestorePosition(self, val): 
     1745        self._scanRestorePosition = val 
     1746 
     1747