April 5, 2019

No News in a While
Dabo is largely in maintenance mode, which is why there aren't any recent news entries.

posted at: 16:20

Jun 12, 2013

Dabo 0.9.12 Released
Please see the Release Notes for v0.9.12

posted at: 16:09

May 23, 2013

Dabo 0.9.11 Released
Please see the Release Notes for v0.9.11

posted at: 23:22

May 10, 2013

Dabo 0.9.10 Released
Please see the Release Notes for v0.9.10 We are working toward 1.0 Real Soon Now.

posted at: 12:05

Feb 18, 2013

Dabo 0.9.9 Released
Please see the Release Notes for v0.9.9

posted at: 15:56

Jan 27, 2013

Dabo 0.9.7 Released

We are gearing up for the 1.0 release, and have put in some changes based on found problems by our users.

Here are the changes: Release Notes for v0.9.7

posted at: 15:27

Dabo 0.9.8 Released
Please see the Release Notes for v0.9.8

posted at: 15:27

Jan 24, 2013

Dabo 0.9.6 Released, and we moved to GitHub

We've transitioned from Subversion to Git, and you can now find us at https://github.com/dabodev/dabo . We do our ongoing work on the 'working' branch and will periodically - hopefully often - bump the version and merge into 'master'.

Version 0.9.6 was released a couple weeks ago, and version 0.9.5 about a week before that. Here are the change logs for each:

Cheers!

posted at: 23:45

Aug 05, 2012

Web Update revision 7219 Posted

Framework:
- Fixed backend TypeError exception raised if connection parameters are passed to the constructor directly, not as dictionary structure.
- Improved performance of connections via the KeepAliveInterval property.
- Improved null value handling in dDatePicker.
- Added several improvements to the dbMsSQL module.
- Fixed an issue affecting PageNumber and PageCount properties

Report Writer:
- Fixed the ResetPageNumber property
- Added printerPort and copies arguments to reportUtils.printReport().
- Broke the save functionality out of the write method into its own save method.
- Added 2 new Group properties: StartOnNewColumn and ReprintHeaderOnNewColumn
- Added 1 new GroupFooter property: PrintAtBottom

ClassDesigner:
- Added support for dCheckList

posted at: 13:49

May 29, 2012

Web Update revision 7192 Posted

- Fixed an issue where grids would ignore the Precision setting with Decimal values.
- Fixed an issue where removing a page from dPageToolBar did not remove the associated tool button.
- Improved the behavior of forms when restoring their window state.
- Reduced flickering of some forms.
- Fixed a bug in the Class Designer that prevented some classes from being edited.

posted at: 13:05

May 10, 2012

Web Update revision 7178 Posted

- Fixed a bug in dGrid introduced in the last commit.

posted at: 14:49

May 09, 2012

Web Update revision 7176 Posted

- Fixed a bug in dGrid that would raise an exception if a grid had no records.

posted at: 14:20

May 02, 2012

Web Update revision 7173 Posted

- Some minor bug fixes since the last Web Update was released.

posted at: 13:35

Apr 30, 2012

Web Update revision 7166 Posted

- Added the Minesweeper game to the DaboDemo app.

posted at: 13:49

Web Update revision 7164 Posted

- Fixed a typo that accidentally made it into the last release
- Updated the translation files

posted at: 09:20

Web Update revision 7159 Posted

UI Layer Changes


- Added a setRowHeight() method to allow programmatic setting of row heights. If SameSizeRows is True, setting any row height changes them all, just as if the row had been resized in the UI.
- Changed the default for Idle events in a form to refresh once per second instead of continuously; this can be modified with the IdleRefreshInterval property.
- Fixed the problem of all grid columns using the default string renderer, even if they had set an explicit DataType.
- Added basic copy functionality to grids. By default strings are enclosed in double quotes, values in the same row are separated by tabs, and rows are separated by newlines. These are all configurable as settings, though.
- Renamed the 'dShell' class to 'dShellForm', and the '_Shell' class to 'dShell', making embedding the shell into other apps much easier.
- Enhanced dHtmlBox to allow link hrefs to refer to application or form methods.
- Fixed a problem that prevented a grid column's DynamicVisible property from being updated when the column was hidden.
- Added a dropped file handler for the interactive shell's editor.
- Fixed dynamic properties issues in dToolBarItem class
- Improved the appearance of dSpinner under Windows.
- Added a check to prevent adding a sizer more than once to another sizer.
- Added a RowNavigationEvent that is raised when the user moves through the data using next(), last(), etc.
- Enhanced the dLinePlot class, and added a demo class for it into DaboDemo.
- Fixed a problem on MacOS where the Preferences menu item would become disabled.
- Made sure that the "check spelling as you type" option works on MacOS.

Bizobj Layer Changes


- Added dBizobj.DataSourceName property, corresponding to real source table name for business object, which allows you to create multiple business objects with same table as source on single form.
- Added new property RequeryChildrenOnNavigate to dBizobj, allowing a way to (temporarily) suspend requerying any child bizobjs when navigating.
- Fixed a problem in dBizobj where setting self.exitScan caused all future scans to exit immediately.
- Added getChangedStatus() to dBizobj, which returns the information in getRecordStatus(), but for all the changed rows in the bizobj, including changed child bizobjs.
- Added explicit support for dBizobj multiple-field search in seek() and locate().

Data Layer Changes


- Added convenience function getFieldVals(), which just decorates input and output to/from getDataSet() to return the dict of field/value pairs in the current or specified row.
- Got SQLite to work correctly with BLOBs.
- Fixed a problem in the many-to-many routines where the cursor was using its KeyField instead of the 'other' tables pkCol.
- Fix dbMsSQL.getFields() method issue handling table names with schema.
- Added dCursorMixin.setDataSet() method to directly populate a cursor's data.

Changes to Tools


- Replaced the old non-working MenuDesigner with a version that actually works.
- Report Writer: Improved the display of memos with more data than can be displayed to show as much as possible, followed by an ellipsis.
- Added dShell support to the Class Designer.
- Added 'Precision' to the exposed dColumn properties in the Class Designer.

posted at: 07:50

Oct 03, 2011

Web Update revision 6866 Posted

General Framework Changes:

- Lots of docstring changes to improve Sphinx documentation
- You can now override the setting of the language defined by locale.
- Changed default Encoding for datasets to the one declared for the backend.
- Added dApp.displayInfoMessage() which presents a dialog with a checkbox for the user to choose if they will see this particular message in the future.
- Added getSharedAppDataDirectory() fuction, which returns application shared data directory.
- Improved debugging by including the current call stack in every callAfter/setAfter call, so that errors can show the path that led to the *after method being called.
- Fixed an issue where calling the _initModuleNames() method would not update with any changes since the app first launched. With this change, bizobjs created or changed in the Class Designer will now be available when test running the class.

Bizobj/DB Layer Changes:

- Augmented the Data Type Mismatch error to show the table name and not just the field name.
- Fixed an issue where newly-added records in cursors that had never been requeried didn't know their data structure, even though DataStructure had been set explicitly.
- Improved the getDataSet() method to eliminate the need for looping through all rows.
- Fixed issue with dBizobj wrong cursor assignment for newly created grandchild cursors.
- Added argument to biz.save() to optionally prevent child bizobjs from getting saved.
- Added the Connection property to dBizobj.
- Multiple improvements in the handling of child bizobjs and changed rows in dBizobj.
- Added an optional TypeStructure property to dDataSet to provide 'hints' to the class in determining data types.
- Fixed the case where seek(..., near=True) worked correctly except in the case where we were seeking a value greater than that of the last row, in which case it would stick the record pointer on the first row instead of the last row.
- Added helper getBizobj() function to dDialog so that controls in the dialog can still find their bizobjs with 'self.Form.getBizobj()'.
- Added basic methods to dBizobj and dCursorMixin for handling many-to-many (M-M) relationships.
- Changed the logic for data binding with bizobjs. Now you can bind to any attribute of the bizobj, not just columns in the bizobj's data set.
- Made some improvements to support for MS SQL connections.
- Changed the value returned by dCursorMixin's RowCount to 0 from -1 for the case where the cursor has not yet been requeried. Logically it makes more sense, and we don't rely on a value of -1 for this anywhere.
- Improved the way that dBizobj's isAnyChanged() method determines changes.

UI Changes:

- Added the 'ChildObjects' property to sizers. This will return a list of the objects managed by the sizer, whether they be controls, sizers, or spacers. The 'Children' property still returns a list of sizer items.
- Fixed the dDockForm and dDockPanel classes so that the properties work again.
- The DataSource property for controls can now be set to a callable, which will be evaluated each time the property is accessed. This makes it possible to have a dynamic DataSource.
- Added the 'moveTabOrderBefore()' and 'moveTabOrderAfter()' methods to improve control over tab order.
- Added the ability to flip displayed images in the dImage control horizontally or vertically.
- Added the ability for dImage to recognize rotation information in image files that store it, and adjust its display accordingly.
- The grid's header area now defaults to white, while the default grid column header background color is grey.
- dGrid's SelectionForeColor and SelectionBackColor weren't settable from initProperties() or from the constructor. Fixed.
- Added the 'UpdateInactivePages' property to the paged controls; this limits propagation of update event to the active page only when set to False
- Pages now have the DeferredUpdates property to handle delayed updates, until page become selected.
- Fixed some flushValue() problems in dTextBoxMixin, and improved its internal data type support.
- Added the ButtonShape property to dBorderlessButton.
- Added ability to associate a node in dTreeView with a file path.
- Fixed the issues with the segfault/bus error with dGrid that was being seen when running the Class Designer under Python 2.7.
- Changed the header context menu in dGrid so that if ResizableColumns is False, the options to autosize the column is not available.
- Changed the background color of column 1 in the demo code for dGrid to something a little less ugly.
- Enhanced the 'makeDirTree()' method to accept a list of file patterns for both including and excluding. Also added checks for upper/lower case versions of those patterns.
- Added the DataUpdateDelay property to dForm to control delay between when business data changes and UI controls get updated; setting to None means that controls are immediately updated with changes.
- Fixed some flickering issues with dForm when refreshing.
- Added the convenience classes dSizerH and dSizerV for making horizontal and vertical sizers, respectively. Yes, I am lazy.
- Fixed problem with some paged controls not properly working with setAll() method.
- The dDockForm classes use the agw version of the AUI libraries if available.
- Added the 'MovableTabs' property to the dDockTabs class; when False, the tabs cannot be rearranged or docked. This must be specified when the control is instantiated.
- Added helper getBizobj() function to dDialog so that controls in the dialog can still find their bizobjs with 'self.Form.getBizobj()'.
- Added the UseSmartFocus property to dPageFrame, which will 'remember' the control that had focus on a page, and reset focus to that control when the page becomes active.
- Fixed dSpinner control flush on update issue.
- Added dDatePicker control based on native wx.DatePickerCtrl.
- Changes the InteractiveChange event so that it is raised after the data source update to better synchronize between biz and UI layers.
- Added global setting autoDisableDataControls to handle new data controls behavior on empty dataset.
- Added ReadOnly property to dRichTextBox.
- Added the ShellCommandRun event, which is raised whenever dShell executes a command in its interpreter.
- Added the PersistSecretData property that overrides IsSecret property allowing to store sensitive data in encrypted form.
- Added the NumericBlankToZero property to dTextBoxMixin. When true, blanking a numeric field will be interpreted as setting it to zero.
- Fixed an issue with dPageStyled where 'select' parameter was by default set to True and fired the PageChanging event on every newly added page.
- Added a Rounded Rectangle to the available DrawObjects.

ReportWriter Changes:

- Deprecated Frameset/Paragraph; Added Memo which accomplishes the same thing in the same way without the developer needing to know about the hierarchy.
- Removed the auto-updating of the _def default properties when the main property changes, as it was causing unneeded cruft in the rfxml.
- Changed default expr of String and Memo to "String" and "Memo", respectively.
- Improved Memo's Leading property to easily be able to specify single- or double-space, and to modify that with any number of + or - chars, like "single+++" to have single-space plus a little bit.
- Added a new report object, "Defaults", with one initial default to set: FontName. If String or Memo don't have FontName explicitly set, the report default will be queried. If that isn't explicitly set, the base default will be queried. The base default is Helvetica, but I suggest installing DejaVuSans or some other true-type font that has extended symbols that will likely be encountered in user data, expecially in non-US locales.
- Bad font names will no longer crash the reportWriter, they'll simply be substituted with Helvetica, Helvetica-Bold, Helvetica-Oblique, or Helvetica-BoldOblique.
- Added code to defend against converting anything other than the most common Frameset/Paragraph. It is possible but unlikely that rfxml's exist in the wild with multiple subobjects of Frameset, and this will keep those from getting converted.
- Add the system truetype font paths to reportWriter, which will result in auto-registration of specific fonts upon first use.
- Fixed an issue with Memos in which data that was too long resulted in nothing being printed. Instead, the message '<<< string too long >>>' will be printed so the developer knows what needs to be fixed.
- Fixed the reprinting of group headers from the printing of a detail band so that they only reprint group headers higher in the list than the current group
- Allow for the image expression to evaluate to None, and just don't print anything in that case.

Report Designer Changes:

- Enhanced the ReportDesigner by making Shift+Enter on an object activate the propsheet editor for the currently selected property in the propsheet.
- Enhanced ReportDesigner to show the paragraph object expression on the design surface. In addition, made it so when you click on the Frameset, the Paragraph is what gets selected. You can still select the Frameset object by clicking on it in the object tree.
- Deprecated Frameset/Paragraph; Added Memo which accomplishes the same thing in the same way but the appdev doesn't need to know about the hierarchy.
- Changed default expr of String and Memo to "String" and "Memo", respectively.
- Changed dynamically-sized bands (height = None) to use height_def for display in the designer, instead of the hard-coded 75pt used previously. If no height_def has been explicitly set, the 75 is still used to avoid the default of 0, which would be confusing.
- ReportDesigner looked horrible on Mac because of dark default background. Fixed.
- Fixed a bug in the designer when changing the height of a band where the height was None (dynamic) previously.

Class Designer Changes:

- Replaced the painted of dSizerPanel with a nested panel. I prefer the look of the painted border, but it flickers way too much due to the excessive number of repaints.
- Added needed self.refresh() after a Zoom operation to avoid artifacts.
- Added code to save/restore the zoom level.
- Changes the layout when editing sizers so that the two panels are horizontally arranged. Previously, the vertical arrangement was too tall for some screen resolutions. Thought I had committed this a while ago.
- The search dialog of the Class Designer Editor will search *all* of your code for the class, and not just the currently displayed method.
- There is now a popup that allows you to quickly navigate to any existing method of any object. To access that popup, click the down triangle in the top left corner of the editor window, or press Ctrl+J to activate the method list.
- Incorporated the ability to edit text files while remaining in the Class Designer.
- Changed the Class Designer to use the directory in which it was started, not the 'ide' directory, as its HomeDirectory.

posted at: 07:50

Feb 19, 2011

Web Update revision 6450 Posted

- dCursorMixin: Refactored CursorRecord out of dabo.db.dCursorMixin into dabo.db. Now both dCursorMixin and dBizobj can use the class to instantiate their own Record instances. This effectively means that assigning to biz.Record.field no longer calls cur.setFieldVal() directly but instead calls biz.setFieldVal(), allowing easy interference to be run by appdev code.
- dBizobj, dCursorMixin: improved handling of compound primary keys.
- New: Wrapped the wx.media.MediaCtrl to create the Dabo dMediaControl, which allows you to add video and audio to your app.
- dPref: Added 'prefDb' parameter that allows to specify an explicit preferences database.
- dBizobj, dCursorMixin: Added the ability to specify which record to setFieldVal() on, by sending the pk of the row to set.
- dGrid: Added the VerticalHeaders property. When True, the header captions are written vertically; i.e., at a 90 degree angle, which is useful if you have narrow columns and need to display a label for the column. Thanks to Bronwyn Woods for the idea.
- dGrid: Added the AutoAdjustHeaderHeight property. When True, the HeaderHeight of the grid will change to fit the Captions, whether they are written vertically or not.
- dGrid: Added dColumn.CellFontBold and DynamicCellFontBold. However, it isn't displaying on Linux. Left comments in place to tackle later.
- dPemMixin: Changed the draw object routines to accept an optional dc for drawing.
- dGrid: Changed the grid header drawing to use the same dc as the rest of the header.
- Added the Object Inspector, which allows you to "inspect" objects in a running Dabo application. It can be activated by pressing Ctrl-Shift-I.
- dPemMixin: Added code to account for platform differences in the way that forms report their absolute position on the screen. Under Windows, instead of the position of the entire form, the position of the interior (minus title bar, menus, borders) is returned.
- dDockForm: Added import of agw version of the AUI classes, if available. Noted that several properties no longer seem to have any effect when changed; will need to look at this in more depth.
- dPemMixin: Improved the calculation for absoluteCoordinates(). It was failing to take into account that for forms, we should always use (0, 0) as the Position from which we calculate.
- dBizobj: Improved the DataStructure changes detection.
- dSizerMixin: Added the 'Form' property to sizers. It will return the form with which the sizer is associated, or None.
- dSizerMixin: Added the getContainingWindow() method that will return the window that contains the sizer, even if the sizer is nested within other sizers.
- Added the ability to embed the _Shell class of dShell in non-dShell forms.
- dToolBar: Added the ToolbarItemClass property, allowing you to define your own subclasses for a toolbar's items. The default remains dToolBarItem.
- dbPostgreSQL: Made a change to the way the rollback was being called, based on a suggestion from Jacek Kałucki who experienced issues with losing a transaction.
- dDateTextBox: Fixed problem with the calendar ignoring the setting for FirstDayOfWeek
- Added some saner minimum sizes in dPemMixin.
- Change in getEncoding() behaviour to use getdefaultlocale() instead of getlocale() function, which returns values usable in the rest of the framework.
- Changed how the UI module is imported into the main dabo namespace.
- Changed the default for self._fontSize from None to 10, as some routines were expecting it to be an int and throwing errors on receiving a NoneType value.
- dabo module: Now initialize localization services *after* the logging system is in place, or dLocalize will cause a traceback when trying to log problems.
- dApp: Refactored dApp.default_form and dApp.formsToOpen into properly-named properties.
- dbFirebird: changed rdb$field_length to rdb$character_lenth on request of Werner F. Bruhin.
- dbFirebird: Improved handling of non-ASCII values in connection parameters.
- dBizobj: Added suppoort for the scanRequeryChildren parameter in the scanRows method to override ScanRequeryChildren property.
- dBizobj: Added the _CurrentCursorKey property.
- dBizobj: Clear the bizobj's cursorRecord when DataStructure and VirtualFields are set, as well as in requery().
- dBizobj: Fix for ticket #1351, where the scan method doesn't update grandchildren bizobjs.
- dBizobj: Limited child bizobj FK updates to the new rows only.
- dBizobj: Moved the setCurrentParent() call outside the check for RequeryWithParent, as the setting of the parent should happen unconditionally. However, this will result in the side-effect of an implicit requery() if the cursor for that key doesn't exist yet, *and* RequeryOnLoad is True.
- dBizobj: Refactored cacheExpired() a bit, with a check for lastRequeryTime being None.
- dBizobj: Removed the recently-added force argument from requeryAllChildren, in favor of adding a note to the docstring that developers should explicitly call self.expireCache() before requerying, which ensures all cursors (not just the current one) in a bizobj will get requeried next time the record becomes active.
- dBizobj: setFieldVals() now calls setFieldVal() for each field, so that the afterSetFieldVal() hook will be fired when the field changes.
- dCursorMixin: Added some verbosity to the class exceptions.
- dCursorMixin: Fixed issue with updating field that is part of compound PK. Now _newRecords reflects such changes.
- dEditBox: Improved the handling of the WordWrap property. Fixed some punctuation in the Love Boat lyrics in the test code that had been annoying me for some time. NOTE: the horizontal scrollbar doesn't seem to be drawn in OS X.
- dEditor: Implemented the select() method for dEditor.
- dEvents: Event logging was displaying '?' when getAboluteName() couldn't find a name for the object. Better to use the default __str__().
- dGrid: Added DrawObject.draw() positioning condition to fix header captions display out of the visible area issue.
- dGrid: Added the SortIndicatorSize and SortIndicatorColor properties, which allow you some control over the appearance of the little sort triangle displayed in the header when that column is sorted.
- dGrid: Fixed _paintHeader() issue if it's called from outside of the OnPaint event.
- dGrid: When using dynamic properties, if you need to call grid.getValue() to determine what dynamic value to return, you would hit an infinite loop. I added a parameter to the overridden GetValue() method to control this.
- dLabel: Fixed an issue where resizing could cause an infinite loop.
- dLabel: Made some changes to how WordWrap works; it was behaving incorrectly on some platforms.
- dLabel: Reduced the flickering in the dLabel demo.
- dLed: control wasn't always resizing properly because of the underlying panel's minimum sizer settings. Fixed.
- dMediaControl: Added the ability to clear the control by setting Source = None.
- dMediaControl: Added the ability to drop Source files on the control and have them loaded.
- dPemMixin: Removed manual Ctrl+A support code for Windows platform, since it works properly since wxPython 2.8.10 version at last.
- dPref: Added the __contains__() method so that pref objects support the "x in y" syntax for determining if a key exists in a given preference object.
- Fixed a problem that was due to the way we were calling the super() of __init__(): we were taking the keyword params 'properties' and 'attProperties' and passing them as non-keyword params. This was causing some subtle errors that mostly manifested in the Class Designer.
- Fixed test.py to set the width of the frame, and not the object themselves. Previously, the MinSize for the object was being set via an explicit Width setting, making resizing problematic. Now the form is sized, allowing the sizer to handle the sizing of the object.
- Grabbed the latest translations from launchpad and added them to the locale directory.
- Modified the getItemIndex() of dMenu method to take either a caption (existing behavior), or an actual menu item.
- Moved the methods that gather system information out of the About dialogs and into the uiwx module.
- On Windows, scriptDir was 'C:\\ss\\ui' while appDir was 'c:\\ss', causing isSubDir() to fail. Fixed but will cause problems if someone has meaningful case-sensitive directory names, but that would seem to be stupid so I'm not worrying about it.
- reportWriter: Added CurrentBandName and CurrentBandObj reportWriter properties, inspired by Nate's ticket #1380.
- reportWriter: Raise an exception if invalid rfxml passed, instead of printing the message and then having an exception thrown because form isn't defined.
- ui module: Added the sendIdle() method to help with thread message processing.
- ui module: the latest wxPython changed the return value of HitTest() to sometimes return a single value instead of a 2-tuple, so code was added to handle this properly.
- Updated dLocalize to not prevent the program from running if the translation for the language is not found. Added support for additional aliases for languages.
- ClassDesigner: Added an option to the dialog that appears when you first run the Class Designer to re-open the last class that you worked on.
- ClassDesigner: added the dMediaControl to the Class Designer
- ClassDesigner: Fixed an issue reported by Sibylle Koczian in which running the wizard for adding controls from the data environment would throw a "String must be present in the choices" error.
- ClassDesigner: Fixed an issue with the restoration of lists and tuples as values in cdxml files. Trac issue #1406.
- CxnEditor: Added provisions for handling application CryptoKey values. Note that when the file is saved, the encrypted password is saved, but not the encryption key, for obvious reasons. In order to re-edit the file, you will have to enter the CryptoKey when opening up a saved file. If the PyCrypto package is not installed, none of the CryptoKey changes will be visible.
- PrefEditor: Removed the custom PrefDialog class, as it is no longer needed.

posted at: 08:20

Nov 22, 2010

Web Update revision 6201 Posted

- Fixed a potential problem when starting Dabo if a default encoding was not set.

posted at: 09:05

Nov 21, 2010

Web Update revision 6199 Posted

- Fixed some WordWrap issues with labels.
- Updated the bizIterator classes. They now have two more optional parameters: 'reversed' (default=False): when True, the rows are returned in reverse order; and 'restorePointer' (default=False): when True, the RowNumber is reset when the iteration is complete. The reverse() method has been removed, as it is no longer needed.
- Removed inconsistencies in the code with respect to the use of 'dabo.settings.something' vs. 'dabo.something' to only use the latter form.
- Fixed some display issues with dSpinner.
- Corrected a problem noted by Fraser Burns in which pathing in file names was effectively doubled, causing "File not found" errors.
- Fixed the menu handling issues that prevented the Most Recently Used ("MRU") functionality from working. Also added support for using MRU with submenus.
- Added optional 'multiple' parameter to promptForFileName().
- Modified the appendMenu(), prependMenu(), and insertMenu() methods to return the menu reference instead of a boolean indicating success. While these methods require the reference to be passed in, I felt that it was confusing since every other append, prepend and insert method returned the reference to the item being added.
- Added references for all the included menus and menuitems to the menu bar. This will allow you to reference them in your code instead of having to constantly locate them.
- Changed the hotkey for Redo to 'Ctrl+Shift+Z' to remove the conflict with the Command Window history shortcut, and to keep it in line with 'Ctrl+Z' for Undo.
- Activating the Code Editing page of dShell now sets focus to the editor automatically.
- Added the 'importDebugger' setting. Default=True, which preserves current behavior. If you are using an environment with its own debugger, override this setting to False.
- Changed the internal order that we process bound events.
- Added type conversion in dSpinner if Max/Min and Value were not both Decimal or Float.
- Fixed incorrect handling of properties when running a design using dBorderSizer.
- Added a 'force' parameter (default=False) to dBizobj.requeryAllChildren() to override any cache settings in those child bizobjs.
- Saving a document in dEditor no longer clears the Undo buffer.
- Added the dBizobj.expireCache() method, which will ensure child records will requery during the next cycle.
- Added the MinSizerWidth and MinSizerHeight properties to dSlidePanelControl, and set them both to default to 100px initially. This will ensure that the control is never sized to zero pixels when given a proportion of 0, as was happening previously.
- Removed duplicate MySQL transaction logging.
- Modified the behavior when setting the Picture property of dImage. Instead of raising an error when set to a non-existent file, it will write to the error log and return.
- Updated the buildwin.bat file in AppWizard-generated apps to better explain the steps needed to build exe files under WinXP.
- Changed the hotkeys in the Class Designer for 'Run Script' and 'Hide/Show Output' to 'Ctrl+Shift+R' and 'Ctrl+Shift+O', respectively, to be more consistent with other tools. Thanks to Fraser Burns for catching this.
- Aded a menu item for "Open Recent" to both the Class Designer and the Editor.
- Fixed a bug that caused a crash when running the Class Designer without an initial file path
- Improved the layout of the "Edit Sizer Properties" dialog of the Class Designer
- Fixed an error when opening a saved non-sizer cdxml form.

posted at: 08:50

Oct 16, 2010

Web Update revision 6108 Posted

- Abstracted out the columns in dListControl. You can now change column captions without losing your data and other column settings.
- General improvement of the dPageFrameNoTabs class
- At the suggestion of Jacek Kałucki, I've added a variation of the bizIterator named 'bizDataIterator', which returns a dict containing the columns/values of the current record in the iteration.
- Added a code editor to the dShell class, allowing you to easily edit blocks of code, and then execute it in the shell.
- Added the locate() method, which returns True/False based on whether the value passed was found in the data. By default the pointer is moved to the matching record, but passing 'movePointer=False' will not change the current RowNumber.
- Added the method 'getEncoding()' to the main dabo module. Updated all code to reference this method when looking for encoding settings. This will make using Dabo with non-ASCII strings much more consistent.
- Added several patches to localization problems courtesy of Jacek Kałucki.
- Fixed an issue in which child bizobjs that did not link to the parent's PK column threw exceptions.
- Converted all the deprecated usages of dict.has_key() to use either the 'in' syntax, or a try/except block.
- Several bug fixes to dMaskedTextBox.
- Added the NoneDisplay property and several unicode patches to reportWriter.py
- Added ability to register TrueType Font files and directories to ReportWriter.
- Fixed a long-standing problem in the reportWriter where the group header would sometimes get
printed twice on a new page.
- Modified dMenuBar so that the DynamicEnabled property is evaluated on each update() call.
- Added the 'charsBeforeCursor()' and 'charsAfterCursor()' methods to text controls, as requested by Brendan Barnwell. By default, they return the character immediately before/after the insertion point, or if there is selected text, before/after the selection. You can optionally pass the number of characters to return if you want more than one. You can also specify that any selected text be included in the return value; by default it is not.
- Made the Choices property of list controls dynamic, in that changes to the value returned by that property will modify the list options of the control. Formerly, you would have to get the Choices, modify them, and then re-apply them to the property. Now you can modify them directly, and have the change reflected in the control.
- Refactored the Ruler class in the ReportDesigner so the instance knows its position, not merely its orientation. This should fix the error Jacek's been getting on Windows XP that I wasn't able to reproduce but could have happened if the Paint event occurred at an unexpected time.
- Added support for dListControl properties to the Class Designer.
- Added support for dMaskedTextBox to the Class Designer.
- Added the newer manifest for setup.py.
- Fixed a bug reported by Jim Byrnes in which dPage instances in the Class Designer did not display a context menu.

posted at: 16:20

Sep 13, 2010

Web Update revision 6020 Posted

+ Cleaned up the code base by removing all trailing whitespace.

+ Removed the ref to md5 and replaced with hashlib. haslib is currently already being used in dDataSet.py and md5 has been deprecated (those users of python 2.4 or less need to install the hashlib.py)

+ Added dabo.lib.reportUtils.printPDF(), and added a print button to FrmReportBase in the AppWizard generated code.

+ On Windows, where the status text can go to the main frame, hidden forms were writing their current record text to the status bar on update. This fixes that awkwardness.

+ Eliminated (or at least greatly reduced) the grid header flickering on Windows.

+ Fixed a bug reported by Mark Rajcok in which the WordWrap property grid columns was only affecting those with str DataType, and was ignoring unicode DataType.

+ Switched all of Dabo's logging to use standard Python logging.

+ Switched from os.system() and os.popen2() to subprocess.call() in previewPDF() and printPDF(). Removes DeprecationWarnings in Python 2.6 and above.

+ Added some logic to prevent infinite loops when using field-level validation.

+ Added a fix so that previewing and printing should be modeless by default.

+ Updated the internal cache code to handle permissions better when running under mod_wsgi.

+ Added the 'SelectedText' and 'Text' read-only properties to dHtmlBox.

+ Added the reports folder to the resolvePathAndUpdate method in the utils module. Added a conditional check in the reportWriter to call the resolvePathAndUpdate method if the path is a valid absolute path. So, now you can specify the ReportFormFile property of the ReportWriter object is a relative path.

posted at: 06:20

Sep 12, 2010

Dabo 0.9.3 Released

It's been way too long since we did an official release, but all that's
changed now: welcome Dabo 0.9.3! There have been many, many changes and
fixes over the last 15 months; here are some of the major ones:

- integration of the native Python logging module for all Dabo logging
- support for DES3 cryptography in Dabo encryption
- changed all pathing to be relative to the app's HomeDirectory
- full parameterization of SQL calls
- addition of the dRichTextBox control
- improvement of unicode support with the dabo.lib.ustr() method

If you're currently using the Subversion repository or Web

Update to keep your copy of the framework up to date, you don't need to
do anything - you already have the code in this release.

posted at: 16:19

Jul 12, 2010

Web Update revision 5924 Posted

- Reverts a behavioral change introduced accidentally in r5846. Now scan() will requery child bizobjs by default.
- Created the 'ustr()' method in dabo.lib.utils. This is designed to replace all of our calls to str() in order to eliminate the unicode encoding errors that pop up frequently when non-American developers use Dabo.
To use, include the line:
   from dabo.lib.utils
    import ustr
in your import statements, and then replace all instances of str(val) with ustr(val).
- Added some sizer outline code to dFormMixin that was inadvertantly left out of the last Web Update.
- dRichTextBox: Changed the 'InsertionPoint' property to 'InsertionPosition' to be consistent with other editing controls.
- dRichTextBox: Renamed the 'loadFromFile()' and 'saveToFile()' methods to 'load()' and 'save()', respectively, as they can use any file-like object.

posted at: 06:20

Jul 07, 2010

Web Update revision 5910 Posted

- Added the dRichTextBox class, which allows for basic rich text editing and display.
- Fixed a bug in Web Update that prevented apps from recognizing that Web Update had not yet been run for that Dabo installation.
- Changed the PreferenceDialog to use a basic dPageFrame instead of dPageList, due to wx warnings.
- Fixed a potential problem in list controls where the control could try to access its value before the correct DataSource had been set.
- Added code to reduce dGrid flickering under Windows.
- Added the ImageRenderer class to display images in grid cells.
- The code that handles dropped text/files now preserves the x,y location of the drop so that you can tell where on the control the user dropped.
- Added a textbox-level NoneDisplay property so that individual text box controls can determine how they display None values instead of all controls using dApp.NoneDisplay.
- Fixed an incompatibility with a recent wxPython change to the foldpanelbar class.
- Several visual improvements to the dPageStyled class.
- Fixed a bug in dSlider that prevented reversed display.
- Fixed some inheritance issues with sizers.
- Improved sizer outlining to be more flexible. This is mostly for app design uses.
- Added support for the dPageStyled class to the Class Designer.
- Added visual indication of sizers in the Class Designer when a sizer is the selected object.
- Added the HomeDirectoryStatusBar to the visual tools to display your current app's HomeDirectory.
- Updated the standard directory structure for Dabo apps to include 'cache' and 'lib' directories.
- Fixed some import errors in reportWriter.py
- Added an optimization to dDataSet that improves performance when doing multiple queries against the same data.
- Added an optional optimization to dBizobj that avoids having to requery child bizobjs during a scan().

posted at: 07:50

Apr 25, 2010

New Screencast: The Dabo Shell and the UI Browse Command

I've just created a new screencast that I wanted to do based on feedback
from the tutorial session Paul and I did at the most recent PyCon. It
was apparent that many people were not familiar with the shell/command
window in Dabo, so I wanted to demonstrate some time-saving tips. Also,
when I demonstrated the dabo.ui.browse() command, John Fabiani noted
that he had never known about it, despite it being available from the
very early versions of Dabo.

The URL for the screencast is:

http://cdn.cloudfiles.mosso.com/c129431/browse_shell.html
( -or- http://j.mp/9r8XL7 )

I also wanted to mention that this is the first screencast I recorded
using Jing (http://www.jingproject.com/), and it's a fantastic product.
The free version is limited to 5 minute recordings, but I think I may
upgrade to the paid version for only $15/year.

posted at: 09:35

Mar 28, 2010

Web Update revision 5765 Posted

- Fixed a bug in the JsonConverter imports.
- Corrected the bizobj isChanged() function to reflect new records as well as modified records.
- Added dApp.AutoImportConnections property. When False, dApp will skip the process of finding and loading dConnectInfo objects from found cnxml files. My app is being enhanced to use cnxml files, but I use my own logic on which cnxml file to use.
- Augmented biz.getTempCursor() with some optional arguments, allowing the appdev to set sql, params, and have automatic requerying before returning the cursor reference.
- dSlider: added the Reversed and TickPosition properties, as requested by Mike Mabey.
- Finally fixed a dMenuItem bug that's been bothering me for (I think) years now. On Windows, sometimes there would be double captions, and the "Close Window" item in the File menu would be corrupted. Apparently, the timing of calling SetBitmap() is crucial: it must happen before SetText().
- Fixed the language problems withthe code to find menus in AppWizard applications.

- dDateTextBox: allows the user to clear the date (set to None) by adding a shortcut ('N')
- dReportWriter: Fixed bug with spanning objects: if the group didn't print for whatever reason, the spanning never started. Therefore, we can't try to draw the object.
- Fixed a bug in dGrid's incremental search on Windows.
- Refactored the 'resolvePathAndUpdate()' method into dabo.lib.utils instead of dabo.ui.uiwx
- Added window scrolling events to dGrid and dScrollPanel, so that your code can now handle them if needed.
- Added optional argument to cur.execute() to convert any ?'s to the backend's paramPlaceholder.
- Made the localization installation process a little more sane, as it seems that it is especially prone to errors. Now, instead of abending when the dabo localization file isn't found, it prints an error and continues. The app will continue to work fine, but no translations will be done.
- Fixed a bug that prevented boolean values in grid columns from being properly restored. Trac issue #1247.
- Added a flag to avoid an unnecessary pointer movement caused by setting the DataSource of the grid to a bizobj after the bizobj had already been created and had its record pointer set. Trac issue #1314.
- The logic for constructing the filtering WHERE clause in child bizobjs has been corrected to by fully paramterized, instead of 'injecting' the value directly into the SQL.
- Fixed a problem when re-opening designs for custom classes. Reported by Martinecz Miklós.
- Added the 'GridCellEditEnd' event, which is raised when a grid cell editor is hidden, whether the value has been changed or not.
- Fixed a potential issue in the Class Designer Property Sheet in which you could be editing the value of a property of one control, and then navigate to a different control and have your change accidentally be applied to the second control.
- Fixed the Crypto property so that setting it to a crypto object will result in the encrypt() and decrypt() methods using that object.
- Fixed a bug in the filterByExpression() method that only replace the first occurrence of a field name in the expression. Reported by Ricardo Aráoz.
- Changed the Face setter to ignore attempts to set it to 'MS Shell Dlg*' font face names, which can happen when a cdxml file created on Windows is opened on Mac or Linux.
- Changed the HomeDirectory setter to write an errorLog entry instead of throwing an exception when an invalid path is passed. Again, this is an issue with moving a cdxml from one system to another.
- Changed the behavior when attempting to set the Face to a non-existent fontface. Instead of throwing an error, an entry is written to the Dabo error log describing the issue.
- Updated dLed to make it data-aware. It can now be bound to a DataSource and DataField, and have its Color reflect the underlying boolean value.

posted at: 12:05

Feb 16, 2010

Web Update revision 5694 Posted

- POTENTIAL BREAKAGE: Revamped the handling of pathing. If you have file path references in your cdxml or cnxml files, this could break your old files. Pathing is now relative to the HomeDirectory of your app, instead of the location of the tool that created the file.
- POTENTIAL BREAKAGE: Updated the internal encryption code to support the use of DES3 cryptography if you have the PyCrypto package installed. There is also a write-only property of dApp called 'CryptoKey': when you set that property, if you have PyCrypto installed, it will create a new SimpleCrypt instance that uses DES3 encryption, with that value as the encryption key. And to avoid having to pass a plain-text value to the app creation, you can set this property at any time, passing either a string or any callable. By passing a callable, you can more effectively hide the way your key is stored; the actual key never has to appear in your code at all. If you have cnxml files created with the old code, they may no longer work. Simple re-run the CxnEditor to re-save them with the new encryption.
- Added the UIAppClass property to dApp. It can be set to a custom subclass of dabo.ui.uiApp, to enable developers to add ui toolkit-specific behaviors.
- Fixed an issue with the cursor's _mementos attribute getting inadvertantly altered by record cloning. Trac #1316
- Overrode the removeAll() method of this control to work properly with the underlying wx control. Trac #1308
- Added some code to ensure a minimal wx version.
- Fixed the problem described by Jacek in dabo-users today where the cursor won't save a new unchanged record even if the bizobj is set to SaveNewUnchanged.
- Fixed a problem in the seek() method when called from the bizobj when the table has a compound pk. Also improved the algorithm for matching and near-matching. Trac issue #1330.
- Major fix to how resizing is handled for panels. Previously, there were cases where panels would get "stuck" at a large size and were not able to be resized smaller. This should fix that problem. Also added the 'Square' property. When set to True, the panel will confine itself to a square shape.
- If a dBizobj.filter() call filters out all records, a NoRecordsException was being raised. This is generally not necessary, so this is now caught. Trac #1331
- Added code to handle the case in dGrid where a case-insensitive search is being done on a string type column with null values.
- Corrects a problem identified by Jacek Kałucki in which some columns that don't have defined data types only get their type corrected the first time a query is run.
- Fixed a bug that only happened if you called the layout() method of the StatusBar. The attribute '_platformIsWindows' had been previously defined in dPanel, but dStatusBar no longer inherits from that.
- Fixed getCaptureBitmap() to use a WindowDC for panels and dialogs instead of the parent's ClientDC.
- Added the StatusBarClass property, which will allow a form to create any status bar subclass that is needed. Defaults to the standard dStatusBar.
- Fixed a problem when using direct object references as the DataSource, discovered by Jacek Kałucki.
- Added biz.hasPK() method. It answers the question "is this PK value present in the dataset?" It doesn't move the pointer or have any side-effects, and is optimized to return the answer to this question as fast as possible.
- Fixed a bug in cdxml rendering: if it contained a boolean value False, it was stored as the word 'False'. But when the attProperties were being read back in, we were doing bool(val) to convert it back, and bool("False") is True.
- Added a bit of verbosity to quickStart(). Also changed it so that it requires an app name.
- Deprecated ShowColumnLabels; added ShowHeaders. Fixed ShowHeaders and HeaderHeight to not have side-effects on each other.
- Fixed some display issues when the grid has at least one column with Expand=True.
- Made history searches in the Command Window case-insensitive.
- Fixed an issue when opening up the preferences dialog for the first time: since no update frequency preference had been set, an error was raised when the frequency radio list was bound to that pref.
- Changed the order in which we import the app subdirectory modules. This is necessary when using a customized uiApp subclass, which would typically be added as a class in the ui module, and then used by overriding the app creation line: app = App(SourceURL=remotehost, UIAppClass=ui.MyCustomUIClass)
- Fixed a typo that caused an exception when pressing when a report object was selected. Now it brings up the default property in the property sheet like was intended.
- Corrected an error when saving/running a non-sizer-based form.
- Enhanced copy/paste in the report designer: if objects from multiple bands are selected when copied, paste them into the same bands instead of the currently selected band. Allows for copy/pasting a header and a detail item, for example.
- The recent change to make dImage a data-aware control had an unintended effect in the Class Designer: saving an image resulted in not only saving the path, but also the complete byte stream of that image in the Value property. This fixes that oversight.
- Added build scripts for Linux to AppWizard. Now you can 'buildwin', 'buildmac' *and* 'buildlin'.

posted at: 15:00

Dec 30, 2009

Web Update revision 5580 Posted

- Added support for the pudb debugger if it is installed.
- Improved the flow when controls have their value changed from an update() call. Now the flushValue() is no longer called, which avoids unnecessary data validation calls.
- Fixed some issues with establishing HomeDirectory when running from the runtime engine.
- Restored the call to flushValue() that was removed in the recent changes to dSpinner. It was breaking anything that used a data-bound spinner, especially the Class Designer.
- Corrected the issues raised by Jacek Kałucki regarding the navigation problems of dComboBox under Windows.
- Made some changes designed to better support images as data-bound controls. Also allowed for the image's Picture property to accept a wx.Bitmap as the image source, as that's what is returned from the clipboard methods.
- Added the convenience methods dabo.ui.copyToClipboard() and dabo.ui.getFromClipboard(). They work with both text and bitmap types.
- Added a menu option to the Dabo Editor for toggling whitespace visibility.

posted at: 09:10

Dec 19, 2009

Web Update revision 5561 Posted

- Fixed the download_url in setup.py to match the current download location. I guess easy_install has been broken for a while. Thanks Carl Karsten for finding and reporting the problem, along with a solution!
- Fixed setup.py to work with pip, per Carl Karsten.
- Fixed a problem in the SQL generation of AppWizard-generated apps when using full text searches.
- Fixed the issues with custom classes in the Class Designer not being properly inherited when running inside other class designs. The problem came down to pathing, as have most similar issues, so I approached it by adding some smarter pathing code.
- Consolidated the logic for app standard directories. Recent changes had not kept the different locations where they were referenced in sync, so now there is an attribute of dApp called '_standardDirs' that is a tuple of the subdirectory names. There is also now a method of dApp called 'getStandardDirectories()' that will return a tuple containing the HomeDirectory and the full paths to all these subdirectories.
- Enhanced the Editor app by adding an option for setting the number of characters before AutoAutoComplete fires, and another option for toggling whether line numbers are visible.

posted at: 12:14

Dec 12, 2009

Web Update revision 5550 Posted

- Added some events to dReportWriter: ReportCancel, ReportBegin, ReportEnd, and ReportIteration. Your code can bind to them like any other Dabo event.
- Fixed an issue when setting the DataSource to a dPref object.
- Wrapped the creation of the status bar to hopefully not give artifacts when created too close to form creation/resize time.
- Updated dSecurityManager and added dApp.LoginDialogClass.
- Lots of functional and cosmetic updates to dSpinner.
- Fixed color settings in dLed.
- Added the EditorStyleNeeded event to support custom styling in dEditor.
- Fixed an occasional problem with dObject.__repr__() calls.
- Removed code that was slowing searches on virtual fields.
- Implemented full parameter passing to backend SQL instead of using string substitution.
- Several bugs in dGridSizer were fixed.
- Added a lib directory into the standard Dabo structure.
- Fixed datanav Form to not keep the edit page active after a delete or cancel if that action resulted in the RowCount going to 0.
- Revert the changes in r5372, which automatically sorted the file extensions passed to any of the getFile-type functions alphabetically.

posted at: 07:47

Dec 10, 2008

Dabo 0.9.0 Released

We are proud (and relieved!) to finally release Dabo 0.9.0, the first official release of the framework in six months. We haven't been taking it easy during that period; rather, we made some changes that clean up some weak spots in the codebase, and as a result can offer a much more solid framework, and are on course for a 1.0 release in the near future.

To do this, we made some decisions that break backwards compatibility. We dropped support for Python versions earlier than 2.4, and wxPython versions below 2.8. Supporting everything is nice to aim for, but completely impractical.

There is also a major addition to the framework: the ability to deploy Dabo applications as true web apps. Imagine: being able to develop a rich internet app using nothing but Python on both the client and server! It's still early in the development process, so it's lacking a lot of the supporting tools, and almost no documentation has been created, but that will be coming in the next few weeks/months. When you deploy your app as a web app, all data access and business logic is on the server, and the framework automatically handles the communication between the client and server. The framework also automatically grabs file changes from the server, making UI updates seamless and quick. Lots more interesting stuff will be happening in this area in the near future, so stay tuned!

You can grab the latest version from the Download Page

A fairly comprehensive list of the changes we've made since the last release can be found here: ChangeLog.

-- Ed Leafe

posted at: 12:50

Jun 03, 2008

Dabo 0.8.4 Released
Six months since the last release, but many improvements have been made! [changelog]

posted at: 16:51

Dec 11, 2007

Dabo 0.8.3 Released
We've gotten good feedback from a number of you - it feels like the number of people trying out Dabo is growing. From now on we'll try to keep to a 5-week point release cycle. But once you download and install a point release, you can always use the new Web Update feature to stay updated. The changes in 0.8.3 can be seen in the change log . Enjoy!

posted at: 13:16

Oct 25, 2007

Dabo 0.8.2 Released
We are pleased to announce Dabo 0.8.2, which has many many changes since the last version, including web update, better performance, more widgets, a preference dialog you can use in your apps, and better database support. For a full list of changes, view the change log . Enjoy!

posted at: 11:35

Oct 11, 2007

Using raiseEvent()

Sometimes, even if you know the framework as well as I do, you re- discover a feature that you had forgotten about. This happened tonight as I was going over the interaction between a grid and its form, so I thought I'd pass it along.

When any of the events that cause the current record pointer to move are handled by the form, it generates a dEvents.RowNumChanged event, to which grids can bind so that they can update their display. The form code looked like:

dabo.ui.callAfter(self.raiseEvent, dEvents.RowNumChanged)

and the event handler in the grid would run this code:

try: self.CurrentRow = self.getBizobj().RowNumber except AttributeError: pass

In other words, the grid knew that the row had changed, but had no idea what the new row was. It had to then get a reference to the bizobj for that grid, if any, and then ask that bizobj for its current row number.

Why is this inefficient? Because the code that raised the event *knew* the old and new row numbers; the fact that they were different was why it was raising the event in the first place. Then I remembered that you can pass data along to raiseEvent(); any keyword parameters you add are set as event data. So I changed the form code to read:

dabo.ui.callAfter(self.raiseEvent, dEvents.RowNumChanged, newRowNumber=biz.RowNumber, oldRowNumber=oldRowNum)

...and now the grid's event handler can just reference those values directly! They will have the same names as the parameter keys:

try: self.CurrentRow = evt.newRowNumber except AttributeError: pass

This may be a small savings overall, but I thought that it illustrated a handy mechanism built into the Dabo event class that you might use to improve your applications.

posted at: 18:10

May 09, 2007

Dabo 0.8 Released

I guess we shouldn't have said that Dabo 0.8 is just around the corner! Oh, well... here it is finally. We've really been ramping up the development in anticipation of 1.0 later this year. Please see the change log for all the details, and grab Dabo 0.8 from the download page. Enjoy!

posted at: 03:21

Feb 27, 2007

Dabo Session at PyCon 2007 available online

Last weekend was PyCon 2007 in Dallas, Texas. We recorded my session on Developing Desktop Applications with Dabo, and have posted the video for those who could not make the conference. It's available at: http://dabodev.com/ pycon2007.

posted at: 15:21

Jan 18, 2007

Dabo 0.7.2 Released (with wxPython 2.8 Support). Dabo 0.8 Around the Corner.

We've released Dabo 0.7.2, DaboIDE 0.7.1, and DaboDemo 0.7.2. These are all stable releases and the most important fix is that wxPython 2.8 is finally supported.

See the ChangeLog, and download here. Enjoy!

posted at: 08:30

Dec 21, 2006

Dabo Runtime Engine For Windows 0.7.1 Released

I've just posted an update to the Runtime Engine that fixes some pathing issues that could arise in a few situations - thanks to Joe Brown for helping me work this out. Otherwise the contents are the same as the 0.7 release.

As usual, you can grab it from the Download Page, or via FTP at ftp://dabodev.com/dabo/win.

posted at: 14:19