DWI is a fairly simple environment for quickly creating
data-driven applications, that is, graphical applications that manipulate
and show info from a database. This environment differs from others in
that it is focused on native GTK/Gnome support through the Glade GUI
designer, and thus allows you to build user interfaces as elegant as
you can make them in Glade.
At this point, this system has enough features to be adequate for creating form-editing and reporting applications. Multiple SQL database vendors are supported through ODBC (http://www.iodbc.org) or libdbi (http://libdbi.sourceforge.net) drivers. There is very simple db-driver infrastructure so its easy to support for additional SQL API's. The system supports all of the basic Gtk widgets, and an additional half-dozen Gnome I/O widgets, such as GnomeDateEntry.
DWI is powered by an 'engine' that has some fairly generic proceedures for mapping 'fields', such as sql table columns or widget values, between each other, and also between other things, such as objects, hash tables and etc. This engine is currently being expanded so that it becomes possible to easily add support for all kinds of new object systems: i.e. for the engine to become a generic re-mapper between not just SQL and GTK but between many differnt types of object systems and data sources/sinks.
Built on top of this engine is a DWI application that parses an XML-based file, the "DWI file", that describes the connections between glade widgets and database tables. Currently, the only way to create DWI files is by hand. Unfortunately, this can be a fairly long and laborious process itself, especially when creating something a bit more sophisticated. In the future, we hope to have an extension to Glade, or possibly an extension to a database-browsing tool that will allow you to graphically make such connections. (Work has begun on such a tool, written in DWI itself).
The grim reality is that DWI won't ever become popular without a graphical designer. Although fairly complex apps can be readily created using DWI, it does have a non-trivial learning curve. When we say "can be created quickly", we mean "days" or "weeks", as opposed to "months" for traditional database application development cycles. Graphical RAD tools have a way of being brainlessly pleasent to use, and give the impression of an even faster development cycle, even though the learning curve is identical.
Note that the design of the XML format is sufficiently generic that it is not directly tied to Glade. It is envisioned that it could be used to create data-driven web pages. That is, Glade is currently the only GUI driver, but other drivers for other GUI's should be possible.
These screenshots show a very basic note-taking application. The screenshots are not of DWI itself, but of a very simple application created with it. Actually, what is shown was created by Glade; you'll have to take my word that there's a database behind this. Note that if you have good glade skills, you can create much prettier interfaces than this.
Here's a screenshot of DWI using the columned-tree widget. Again, not much point to this, other than to show that DWI does support displaying the results of SQL queries as columned trees (which can be tricky).
To create a DWI application, you need to know SQL, and you need to be able to write XML files. You do not need to program in C or any other language. The dwi-run interpreter will run the entire application based on the DWI file. The testbasic.dui file describes the basic note-taking application whose screenshots are shown above. This example file works as a tutorial; it contains almost complete documentation of the file format.
A graphical editor, to automate the creation of these XML files, is being developed; its currently in the pre-pre-pre-alpha stage. Its being written in DWI itself, and so should prove that DWI can handle 'real-world' apps (as well as implifying the bootstrapping of the editor).
The HINTS file provides some HOWTO-type suggestions for implementing application features, and should give you a hint of what is possible in DWI.
The DWI distribution also includes an example of how to query for a username/password, for database login, and an example of how to use well over a dozen different kinds of widgets within DWI.
Downloads are here; but see also the sourceforge project site: it may have better bandwidth. The current version is 0.2.3. It works; we could call it 1.0, but more is planned.
DWI is now located at SourceForge; The DWI Project Site is a good place to report bugs and make other postings and comments.
Note that the DWI design is fundamentally "declarative" in that it essentially is like a declarative language. For example, an "SQL Trigger" is a declaration: by itself, it doesn't do anything. However, it does describe what should happen in a particular situation. DWI is similar, in that it describes what should happen when a user presses a button. DWI is a way of describing the chain of events, how things get hooked up to things: a button press can cause the value of a widgt to be used in an sql statement, the results of which are used to fill in another table widget. This description or "declaration" of the chain of events makes DWI very very different than proceedural languages such as C, FORTRAN, Python or perl. The point behind this is that its a lot easier to describe the chain of events, than to write programs in C or perl (or scheme for that matter). The 'ease of use' of DWI depends on it being declarative in nature.
The declaration of the chain of events is done using XML. (It might be interesting to use a non-XML way of describing the chain of events, but XML is adequate, if a bit klunky.) The "run-dwi" evaluator reads in this static declaration file, and sets up engine structures that correspond to the XML declaration. Then the evaluator goes into the main loop, and signals and events make everything happens according to the pre-determined definitions in the XML file. There is no run-time interpretation. There is no 'just-in-time' compilation. It just runs along the fixed paths, where each path had been pre-defined in the XML file, and each run-through is initiated by the user clicking or typing in the GUI.
A DWI "application" consists of one or more <database> sections, each of which consists of one or more <window> sections. The application windows themselves interact with the user as a <report>, displaying data, and/or as a <form>, collecting user input. Here is an example file.
A brief but important note about the words "report" and "form". These two words provide the key conceptual underpinning for the DWI XML file format. DWI distinguishes between 'data sources' and 'data sinks'. When one writes a DWI file, one declares the 'pipes' that run between GUI data sources/sinks and database sources/sinks. When a 'pipe' connects GUI data sources to an SQL statement, this 'pipe' is given the arbitrary name "form". The 'pipe' that connects a database record-set (query result) to GUI elements (sinks), this is a "report". For programming architectural design reasons, these pipes are always one-way. But, of course, at the user interface level, you want to have any given widget to possibly be both a source and/or a sink. So, for instance, I can have a GtkEntry act as a source for one (or more) "forms". That just means that the value of the GtkEntry is read, and used to formulate an SQL query. And I can have that same GtkEntry also be a 'sink' for a report: for example, a report that puts today's date into the GtkEntry. So any given widget can be a be a source or sink (or both, several times over, in a one-to-many relationship). However a "form" always inputs, and a "report" always outputs.
A DWI application contains a rudimentary mechanism for handling application state: a global set of key-value pairs (implemented as a hash table). You can create a key-value pair at any time, and later use the values in database queries or in reports. Most form-entry/reporting applications will typically not need to maintain state; more complex applications will typically use global state to map tree-like/hierarchical structures into the database. In addition to the global key-value storage, values can be set and retrieved on individual widgets (using the widget data field).
Whenever a value is obtained from a widget, with the intent of putting it into the database, or from the database, with the intent of putting it in a widget, it can be passed through a "filter". The filter transforms the value in some way, such as stripping out leading whitespace, checking for null, or putting it through a lookup table. Currently, only a very minimal set of filters have been defined; although more are envisioned. (Basically, what's there seems nearly enough, although a good date-format filter would be nice.)
Many Gtk and Gnome widgets can be used for user input and display, such as GtkEntry for string input/output, GtkLabel for string output, and GtkCheckButton displaying/getting boolean values. Most Gtk and Gnome widgets for which it "makes sense" to set or read a value are supported. An effort was made to set values that 'make sense': thus, setting the value for a GtkCheckButton sets the state of the button as checked or not checked, instead of setting the button label. However, setting the value for a GtkButton sets the button label, since it doesn't 'make sense' to set anything else. Note that some 'unusual' I/O widgets are supported: for instance, the window title can be set on GtkWindow, as well as the label on a GtkFrame.
Sometimes it is useful to set other attributes for widgets, other than the 'obvious' one. To do this, the GtkArg mechanism is supported, thus allowing any and every attribute on any and every widget to be set. Thus, for example, the height of a widget can be set by specifying arg="GtkWidget::height", and using a value pulled from a database. More useful is perhaps making a widget conditionally sensitive to input (grayed out or not grayed out), with arg="GtkWidget:sensitive". The 'testwidgets.dui' example shows a large variety of widgets, as well as the usage of args.
Note also that the GtkCList and GtkCTree widgets are supported for multi-row input/output. The GtkCList ("columned list") widget is a basic, simple table, and is 'automatically' filled by DWI. The GtkCTree widget is a hierarchical columned tree; its a bit harder to fill out, as each sub-tree requires a separate database query.
Currently, DWI ignores data types, and treats everything as a string. This may change in the near future. Since SQL database table definitions are typed, there is a natural pressure to put this kind of typing into schema designers and the higher level app (such as MS Access). So far, however, there seems to be no particular need for typing within DWI. So we've resisted it.
"Meta" operations, such as table browsing, are supported, but barely. Other operations, such as dynamic form generation, are currently not supported. These "meta" operations are needed if one wants to build a database browser (or a graphical DWI designer!). Almost all "normal" data-driven applications do not need these features: tables and forms are predefined, and are tailored for the application. However, because they are needed for a DWI designer, they are mentioned here. The current plan of attack is to convert all DWI internal structures to GObjects, so that they can be treated as if they were widgets themselves. This adds a fair bit of mind-bending abstraction to the design and use of DWI, and so we are proceeding slowly to minimize mistakes.