Simply put, Jester is the GUI interface to Bmd. It uses Bmd's crude api functions to read and manipulate the flatfile database. So far, it has received the least attention, and I think it shows. I'll be the first to say it's lacking a zillion important features.
Jester attempts to show databases as a notebook of tables of entry cells. These cells can be modified to change values. The line numbered buttons on the left can be used to select rows for rejection (deletion). The reject tables are separated from the normal and static tables since they will generally not the center of attention. They get a separate notebook of tables. The View pull-down menu switches between them. A quick visual survey of the program running will tell you a lot about its structure.
Eventually, Jester needs to help manage the incoming changes from other people's instances. That means it will need some of hostsurvey's capabilities. It should also help the user enter new data by hand. It's severly lacking in that area right now. You can enter records into each table individually, but there should be some support for input forms. That should help newcomers understand how to use the data.
Jester's code is done in Perl using the Gtk+ bindings. I chose Gtk because of its licensing, popularity, and supposed portability to windows. I've had trouble getting it to work on Windows, so could anyone help in that direction? I've been teaching myself Gtk here, so if there are any more experienced people out there, I could really use some help.
I make extensive use of the user_data field in each widget. I'll start with that $dbradio variable. First, the View pull-down menu allows you to switch to other databases assuming you have more than one open at once. The $dbradio variable always contains a reference to the radio button with the currently active bmd's indexfile name. Every time a new database is opened, a new radio button will appear in that menu, and the $dbradio variable will take on the new widget reference.
Each dbradio widget has an array reference in its user_data field. That array has several database specific values.
$dbradio->user_data = [$bmd,$dirty,$lastnbradio,$nb_norm_stat,$nb_rejects]
$bmd is just the bmd object for this database. $dirty is a one or zero indicating modification. $lastnbradio indicates which dataspace notebook was visible in case the user decides to switch to another database. It's used in the menu_dbswitch sub. The last two elements contain the actual notebook widgets for normal/static tables and reject tables respectively.
As long as we're on dataspace notebooks, the View pull-down menu has another radio button system for switching between those notebook pairs. This one always has two options, naturally. I've merged the normal and static dataspaces into one notebook, because it makes sense to view them together. The reject tables, however, seem like they need to separated. Anyway, the $nbradio variable is another global worth knowing. It will always report the current radio button widget, but not the actual notebook widget that's visible. $nbradio's user data kind of knows that. It contains a single number which is either a three or a four. That number is supposed to be and index for the $dbradio->user_data array.
$nbradio->user_data = ${index into $dbradio's user_data array}
The main VBox that all these notebooks sit inside keeps track of its last child widget in its user_data field. It's usually one of the tabbed notebooks of an open database. If there are no databases open, then it contains a label widget called $introlabel.
$vbox->user_data = $childwidget # could be a notebook or $introlabel
Every tabbed notebook keeps a list of its Gtk::Table widgets in its user_data. They should be in the same order as the tabs appear from left to right.
$notebook->user_data = [$table0, $table1, $table2, ...] # table widgets
Those table widget have a lot of stuff in their user_data fields. They each know their table names, plus two lists of child widgets.
$table->user_data = [$tablename, [@2d_entrylist], [@buttonlist]]
The button list array is simpler, so I explain it first. It, quite simply, contains a list of the line number button widgets in numerical order.
@buttonlist->user_data = [$button_line1, $button_line2, $button_line3, ...]
The $tablename is just a string, but the other two elements are array references. The @2d_entrylist array has a list of all the table's Gtk::Entry cells. There is one for each value, and they are arranged in row major order so a full record is in each row.
Each of the Entry widgets keep their current row number and field number in their user_data fields. These numbers start counting with zero so they can be used as array indexes easily.
$entry->user_data = [$recordnum, $fieldnum]
The gettableinfo function is very commonly used throughout the entire code. It returns an array containing most of the database and table information stored in the user_data fields discussed above. It usually returns info on the current table, but you can specify another by table name. Its output looks like this.
($bmd,$notebook,$tblwidget,$tblname,$dataspace,$entrylist,$buttonlist) =
&gettableinfo();
($bmd, $notebook, blah, blah) = &gettableinfo($tablename);
$bmd is the Bmd.pm object of the currently open database (unless you supplied another $tablename). $notebook is the notebook widget that contains the current table or the specified table. $tblwidget is the Gtk::Table widget like you'd think. $tblname and $dataspace are the strings for the table's name and dataspace (normal, static, or reject). $entrylist and $buttonlist are actually array references. They are the same array refs that are kept in the Gtk::Table widgets' user_data fields as discussed before.