Project Notes


Project: dbSwing: PickList and Status Events Sample
Author: JBuilder Team
Company: borland.com
Description:
The main purpose of this sample is to show how to define and use a wide variety of JBuilder picklists. It also demonstrates status message handling and the use of dbSwing models and binders to make a standard Swing component data-aware.

What this sample demonstrates

Picklists and lookups

DBListModel and DBListDataBinder

Handling status messages

Exception handling

Additional notes

Setup

This sample requires that you have JDataStore installed and read/write access to the sample IntlDemo.jds JDataStore database in the samples/JDataStore/datastores directory. The sample tries to dynamically determine the proper URL to IntlDemo.jds, but since the location is dependent upon the location of your JBuilder installation, it might not always succeed. It writes a message indicating the URL which it is trying to use. If you are unable to run or design the sample, you should explicitly specify the URL to IntlDemo.jds correct for your installation in PickListsFrame.java.

If you have not installed JDataStore, please install it before running this sample. Follow the instructions on Installing JDataStore in Developing Database Applications.

This sample borrows IntlDemo's data but it doesn't enforce IntlDemo's data consistency rules: we don't add line items for each new order, we don't calculate order totals, we don't automatically number orders and keep track of the next available order number, and so on. To prevent changes that might cause trouble when the IntlDemo application is run, we've disabled saving of changes. We recommend that you add or modify any data you need to experiment with this application but let all your changes be discarded when you exit.

Picklists and lookups

Background: A picklist lets you limit the values that may be entered into a column; instead of letting users type freely, you restrict them to choosing from a set of values that is displayed in a list. This ensures that only allowed values are entered into the column. Usually, the value selected from the picklist is entered into the field being edited, but a a picklist can instead or in addition fill related values into related fields.

A lookup seems quite different from a picklist: it is a way of translating the values in a column, for instance by displaying each customer's name instead of their Customer Number. The actual data type and contents of the column does not change - in this example, it is still a column of numbers - but the displayed contents (and data type, sometimes) do change. A lookup is used to display data, while a picklist's main purpose is to control editing of data.

What picklists and lookups have in common is that they are similar in their internal workings and in the way you define them. Both are defined by the pickList property of a data set column. The picklist definition points to a column in another data set, called the picklist data set, that provides the list of all allowed values for the column whose picklist is being defined. Selecting a value from the list identifies a row in the picklist data set. The picklist definition also specifies which values from this row should be filled into which columns of the data set being edited. A lookup borrows this part of the picklist definition to specify which row in the picklist data set provides the translated value for each column value.

In dbSwing, picklists and lookups are displayed through JdbList and JdbComboBox components. A combo box component takes up less space than a picklist component, so is generally more useful. But a picklist component has the advantage that it displays some or all of the values we're selecting from all the time. The main picklist here - the one that changes as you select different options - results from setting the picklist property of the Customer Number column in the ORDERS data set. This column is displayed in a JdbComboBox. The values in this picklist come from the Customer Number column of the CUSTOMERS data set. We've also defined a picklist on the Payment Method column of the ORDERS data set, which is displayed in a JList. This is intended as a demonstration of DBListModel and DBListDataBinder.

At runtime: Select picklist, fill-in, and lookup options in the panel at the left and see how they affect the display and editing of an order record.

Every available combination of options creates a different picklist. That's why picklists are sometimes hard to understand - because there are so many choices. By the way, what we call Name Lookup in Drop-down isn't a distinct picklist descriptor option - we just choose to display a different column from the picklist data set. We show it here because it's a useful variation.

You may want to experiment with picklist options here until you like what you see, find the call to setPickList() that corresponds to that set of options, and model the code in your application after it. Calls to setPickList() in PickListsFrame.java are grouped and commented so you can find the one you want. You can even copy the parameters from this call into the only call to SetPickList in jbInit, then switch to design mode, open the editor for the picklist property, and see what settings in the editor give the desired results. One thing to keep in mind when you open the picklist property editor: in this sample, columns in the CUSTOMERS data set have the same names as columns in ORDERS. So in our calls to setPickList(), the second and fourth parameters are always identical: the second parameter is the list of columns in CUSTOMERS to copy from, and the fourth parameter is the list of columns in ORDERS to copy to. It would be clearer if the source and target column names differed, but they don't in our data sets.

DBListModel and DBListDataBinder

dbSwing's DB...Model and DB...Binder components are used to make non-data-aware components data-aware. In this sample, we add data-awarenss to a standard Swing JList. The result doesn't look very exciting - in fact, it looks and works just like a regular JdbList - but it demonstrates the concepts involved. The more interesting case is when you have a component you've written or obtained from another source that adds significant new behavior to a Swing component, but is not data-aware. Then the ability to easily connect the component to a data set can be valuable. The component must extend a Swing component, and its model must be appropriate for the the Jdb...Model and/or DB...Binder that you use. Here, we use a DBListModel to fill a picklist from a data set, and we use a JdbListDataBinder to set the selection in the list from the value in a column of another data set and to write new selections in the list to that data set.

Ordinarily, a data set is opened when a component that is bound to it opens. When you use a dbSwing model, you must open its data set. Similarly, when a dbSwing binder is bound to a component indirectly - because you have set its model property to a model which in turn is bound to a component - you must open its data set.

Here's how you can see the JList's data-awareness in action at runtime: Select the Payment Method page of the tabbed pane, insert a new row ("Discover", for example), and save it. Back on the Order Form page, notice that the list of values for Payment Method has been notified of the change by the DBListModel, and therefore includes the new value. Navigate through the Orders data set, and notice that the selection in the JList component changes to show the correct payment method for each order. Change an order's payment method and save the changes. Confirm on the Orders Table page of the tabbed pane that the change was made. This is done by the JdbListDataBinder.

Handling status messages

Background: Messages on the JdbStatusLabel come from a number of sources. There are:

Note: If an application includes a JdbNavToolBar but not a JdbStatusLabel, the dialog that displays ValidationExceptions will be suppressed. If you include a JdbNavToolBar in your application, it is a good idea to include a JdbStatusLabel as well, unless you write your own exception handling.

Before it displays a message, JdbStatusLabel sends a StatusLabelEvent to all registered listeners. By writing a listener for StatusLabelEvent, you can suppress or modify status messages. When the listener wants to modify a message, it writes its desired text to the JdbStatusLabel using setText() and throws a VetoException, which instructs JdbStatusLabel to do nothing further with the StatusEvent. If no listener vetoes a StatusEvent, JdbStatusLabel displays it as usual.

You might use a StatusEventListener to suppress non-essential messages or to add additional detail to terse messages. In this sample, we simply add an icon to each message to show its type. We define three types:

You might use the code in a StatusLabelEvent to define more or different categories. We also use our StatusEventListener class, PickListsStatusListener, as a place to centralize JdbStatusLabel operations. Our application's messages to the status label, which are normally outside the StatusLabelEvent mechanism, are all written from PickListsStatusListener.

At runtime: Notice the status message when you change a picklist definition or toggle combo box editability. The icon is intended to show that the message comes from the application. Try to save an Order row with the Last Name or First Name field blank; now the message and icon indicate that this input is not valid. Other messages, mostly of the form "Record n of m" come from the statusLabel itself or from data set StatusEvents; they have a third icon that shows that their source is a data set.

Exception handling

StatusEvents are related to exception handling. JBuilder's default exception handling is this:

You can customize the dbSwing exception dialog by dropping DBExceptionHandler from the component palette into your application and setting its properties. JBuilder doesn't automatically create a new instance of DBExceptionHandler. Instead, it calls getInstance(), which ensures that there's only a single instance of DBExceptionHandler in the application. This lets you set properties for the exception dialog once and have them used throughout your application. If you like the default exception dialog, you don't even need an instance of DBExceptionHandler. Just call its static handleException() method in catch blocks in your code, passing it the exception.

If DBExceptionHandler doesn't give you enough control, you can instantiate the dialog it displays, DBExceptionDialog, set properties of the dialog, and call its show() method. But unless you feel strongly about the look of the dialog or want to change the text of an error message, this isn't worth the effort.

For more control over exceptions, you can implement the ExceptionListener interface. To register as a listener, call DataSetException's static addExceptionListener() method. To ensure that this static reference is never garbage collected, create an object data member and set it to DataSet.class:
Object classHolder = DataSet.class;
Handle exceptions in the ExceptionListener's exception() method. In this case, you must handle all exceptions yourself. You can't call handleException(); if you do, the handler will send the exception right back to you (because you've registered as a listener), causing a stack overflow.

In this application, we just set a property on the exception handler and use it in a catch block. To see the exception dialog, change the file name of one of the icons that's loaded in PickListsStatusListener's constructor to an invalid value. Run the application and you'll see the exception dialog.

Additional notes

Using Data Modules: If this were a realistic application, we would have included a reference to IntlDemo's data module in PickListsFrame.java instead of defining queries and setting column properties. This would ensure that our view of IntlDemo data was the same as that of other users and that our edits obeyed all constraints and data consistency rules. It is only because our purpose is to show off a wide variety of picklists and lookups in a stand-alone sample that we've defined our data sets and columns from scratch here.

Tabbed Pane: This sample uses Swing's JTabbedPane to fit a lot of components onto a single frame. Here's what you need to know to work with JTabbedPane in the UI Designer:

Tooltips: Tooltips are used in several places to explain the expected input:

dbSwing tools: In addition to DBExceptionHandler, which is discussed above, the dbSwing samples demonstrate two other valuable and easy-to-use dbSwing components: