Chapter 16

Online In/Out Board


CONTENTS


lunch \lunch\ n: a meal eaten at midday

Introduction

Welcome to your fourth sample intranet application. Lighter on the complexity side than the last one, this program utilizes the existing employee table to provide an Online In/Out Board.

You might not be familiar with the concept. Many companies use a chalkboard or whiteboard with each employee's name on it. Next to the name of the employee is his or her location, indicating whether he or she is in or out of the office. These boards are commonly placed where administrative assistants can easily see who is in or out. There is an online version that is representative of the same concept.

This chapter will cover the following topics in regard to the Online In/Out Board application:

This four step format will be used throughout all of the sample application chapters. Hopefully, it will provide you with valuable insight and ideas for creating your own intranet applications.

Application Design

This application is one of the simpler applications in the book. Once the application has been connected to a data source, it will present the user with a list of all the employees on file. In addition, their current location, in or out, will be shown.

Figure 16.1 is the proposed user interface for the Online In/Out Board program.

Figure 16.1 : The Online In/Out Board user interface.

The interface will utilize a List component to display employees, and a single Toggle button will toggle the employee's status.

Once the list has been presented, the user may select an employee and press the Toggle button. This button toggles the current in/out indicator from yes to no, or vice versa, depending on the original value of the indicator.

The Toggle button will not become enabled until an employee has been chosen. This visually informs the user that he or she can then do something with his or her selection.

Figure 16.2 shows the application with a selection made.

Figure 16.2 : The Online In/Out Board with the employee Karen Kenny selected.

In addition to pressing the Toggle button, the user will be able to double-click the selection to achieve the same effect. (See Figure 16.3).

Figure 16.3 : The Online In/Out Board after we've toggled Mr. Kenny out.

Finally, the list needs to be refreshed periodically. A timer should be used to automatically refresh the list at a configurable period of time. The default is 60 seconds. You can override this default value by placing a refresh.rate property into your configuration file. 60 seconds is probably an optimal setting. If you set it any lower, you'll just be clogging your network and database with unnecessary requests. If you go higher, you may miss out on changes at lunch- time.

Database Design

This application utilizes the employee table that was defined in Chapter 13, "Employee Files." It toggles the in_out_ind column value from Y to N, and vice versa. For your convenience, the layout for the employee table is shown in Table 16.1.

Table 16.1 Layout for Employee Table

DescriptionColumn Name Type
Null?
Default
Employee IDemp_idnumber( 5 )
N
None
First Namefirst_name char( 40 )
N
None
Middle Namemid_name char( 40 )
Y
None
Last Namelast_namechar( 40 )
N
None
Social Security Numberssn char( 15 )
Y
None
Address Line 1addr_line_1 char( 80 )
Y
None
Address Line 2addr_line_2 char( 80 )
Y
None
Citycitychar( 80 )
Y
None
Statestatechar( 80 )
Y
None
Zip Codezip_codechar( 20 )
Y
None
Salarysalarynumber( 7,2 )
Y
None
Home Phone Numberhome_phone_nbr char( 20 )
Y
None
Work Extension Numberwork_ext_nbr char( 20 )
Y
None
In/Out Indicatorin_out_ind char( 1 )
N
'N'

Implementation

In the rest of this chapter I will discuss the implementation of the Online In/Out Board program. I'll first discuss the user interface and how it was created. Secondly, I'll discuss the database access used in the program. Finally, I'll cover any programming pitfalls that came up during the application construction.

Each sample application in this book uses a different approach to developing the user interface. This variety will show you the different ways you can go about doing your own interfaces. Hopefully, you will get a nice cross-section of many different styles and choose the one that suits you the best.

User Interface

To achieve the design goal presented above, you do not need special user interface components; the stock BorderLayout is sufficient. You'll also employ the List class and a Button.

The following is the user interface construction code for the Employee program:

//****************************************************************************
//* Members                                         &nb sp;                        *
//****************************************************************************

    List                        empList;

//****************************************************************************
//* Constructor                                          ;                     *
//****************************************************************************

    public
    InOutBoardUI( SimpleDBJiflet jiflet )
    {
        super( jiflet );
        setLayout( new BorderLayout() );

        empList = new List();
        empList.setFont( new Font( "Helvetica", Font.BOLD, 14 ) );
        add( "Center", empList );
        empList.enable();

        JifPanel p = new JifPanel();
        p.setLayout( new FlowLayout( FlowLayout.CENTER, 5, 5 ) );
        saveButton.setLabel("Toggle" );
        saveButton.disable();
        p.add( saveButton );
        add( "South", p );

        //    Set the focus to the first field...
        setFocus( empList );
    }

First, set the layout to a new BorderLayout. The List component is created and placed in the center of the layout. This is your employee list. Referring to Figure 16.1, you'll see that this list expands on all sides to fill the space.

Caution
The default layout for the JifPanel class is FlowLayout. Because the SimpleDBUI class extends the JifPanel class, its default layout is also the FlowLayout. Therefore, if you want a different layout, you must create it and set it here.

Your Toggle button is next. In order to get the automatic record saving mechanism to work in your favor, I'll rename the Save button to Toggle. This button is also disabled.

Overriding the saveRecord() method and placing any customized row saving codes in it frees you from monitoring for special events, or even a new button's events. For example, if you want to change the Save button's name to something like Play, you could then override the saveRecord() method to receive notification of this being clicked. I'll cover this in the database access section later in this chapter.

Figure 16.4 illustrates the layout of this application.

Figure 16.4 : The layout of the Online In/Out Board.

Handling the Toggle Button

You want your Toggle button to enable, or light up, when the user has made a selection. This is easily done by looking for the correct events. In your handleEvent() method, use the LIST_SELECT and LIST_DESELECT events to enable and disable the button:

//****************************************************************************
//* handleEvent                                     &nbs p;                        *
//****************************************************************************

    public boolean
    handleEvent( Event event )
    {
        //    Turn on/off buttons...
        if ( event.target instanceof List )
        {
            switch ( event.id )
            {
                case Event.LIST_SELECT:
                    getUIPanel().saveButton.enable();
                    return( true );

                case Event.LIST_DESELECT:
                    getUIPanel().saveButton.disable();
                    return( true );
            }
        }

        return( super.handleEvent( event ) );
    }

Your Toggle button is really the Save button in sheep's clothing: You change the text on it to say Toggle. Changing the text does not alter its behavior. It still generates JifMessage.SAVE application messages in your framework.

It still generates these messages because, instead of checking the text of the button when the initial ACTION_EVENT event is generated, you check the event's target with the member instance variables for all the buttons that you created in your base SimpleDBUI class. Checking the text is a potentially unreliable way to match commands.

Tip
Try not to rely on the text of a component to identify which component it is. This practice is somewhat unreliable and can be misleading. Also, if someone comes along later and changes your program, they could introduce a new component with duplicate text. This could potentially harm your program. Be careful!

What does this all mean to you? It means you can reliably change the text of the Save button. When this occurs, you will receive notification of the event by having your saveRecord() method called.

To handle the Toggling of the selected employee, you will utilize this saveRecord() method:

//****************************************************************************
//* saveRecord                                       ;                         *
//****************************************************************************

    public boolean
    saveRecord()
    {
        return( toggleListItem( ( ( InOutBoardUI )getUIPanel() ).empList ) );
    }

Retrieve the user interface panel's empList variable and pass it to your Toggling function for processing. The result is returned.

Capturing Double-Clicks

In addition to the user pressing the Toggle button, you want the user to be able to double-click the mouse on an employee. This double-clicking will toggle the in/out status of that employee.

This is handled in your action() method. When a List component receives a double-click, it generates an ACTION_EVENT event with itself as the target. What you need to do is capture this event. Call your Toggling routine:

            //      If list was double-clicked
            if ( event.target instanceof List )
                  return( toggleListItem( ( List )event.target ) );

The List is the target of the event, therefore you can simply pass it along to your Toggling method.

Database Access

This program reuses the EmployeeRecord object that was introduced in Chapter 13. It is a versatile class that represents a single row in the employee table. This DBRecord derivation knows how to create, read, update, and delete records from the employee table.

Note
The EmployeeRecord and other database classes are reused in several other applications. They have been placed in their own package along with other shared code. This package is called jif.common. It contains all the common classes between all the applications.

There are two main database access areas to this program: the initial status retrieval and the storage of new statuses. I'll examine each one individually.

Retrieving All the Statuses

At startup, and during the lifetime of the application, the database needs to be queried, and the results displayed for the user. These results are massaged data columns taken from the database.

Retrieve the status of all employees for display:

//****************************************************************************
//* loadPanel                                       &nbs p;                        *
//****************************************************************************

    public void
    loadPanel()
    {
        //    Make sure we're cool to go...
        if ( getConnector() == null || !getConnector().connected() )
            return;

        String sql = "select * from emp order by last_name";

        //    Clear out the old stuff...
        getUIPanel().clearScreen();

        try
        {
            if ( getConnector().getStatement().execute( sql ) )
            {
                ResultSet rs = getConnector().getStatement().getResultSet();

                int row = 0;

                while ( rs.next() )
                {
                    EmployeeRecord er = new EmployeeRecord( rs );
                    setDBRecord( er );
                    getUIPanel().moveToScreen();

                    //    Keep a map...
                    rowMap.insertElementAt( er, row );
                    row++;
                }
            }
        } catch ( SQLException e )
        {
            errorLog( "Error during loading: " + e.toString() );
        }

        return;
    }

This method issues an SQL query that returns all of the employees in your employee table. Each returned row is stored into an EmployeeRecord object. The stored row is then placed into a Vector for later use.

Notice that the employee list is never populated here because you've placed that code in the moveToScreen() method of your user interface class. It is only there that data is moved to the screen. Before it can move data to your list, though, you need to tell the base class which DBRecord to use. This is done with the call to setDBRecord().

The moveToScreen() code is simple:

//****************************************************************************
//* moveToScreen                                       & nbsp;                     *
//****************************************************************************

    public void
    moveToScreen()
    {
        if ( getJiflet().getDBRecord() == null )
            return;

        //    Cast one off...
        EmployeeRecord er = ( EmployeeRecord )getJiflet().getDBRecord();

        String s = er.first_name.trim() + " " + er.last_name.trim() + " is ";

        if ( er.in_out_ind.equalsIgnoreCase( "Y" ) )
            s += "in";
        else
            s += "out";

        empList.addItem( s );
    }

Here, you retrieve the EmployeeRecord from your jiflet, concatenating the first and last names with a string representing their present location-in or out.

Toggling an Employee's Status

Once an employee has been selected, and the intention to toggle his or her status has been made clear, the toggleListItem() method comes into play:

//****************************************************************************
//* toggleListItem                                        ;                    *
//****************************************************************************

    public boolean
    toggleListItem( List theList )
    {
        String         newInOut;
        int         idx = theList.getSelectedIndex();
        String         si = theList.getSelectedItem();

        //    Break down the selection...
        StringTokenizer st = new StringTokenizer( si, " " );

        String first_name = st.nextToken();
        String last_name = st.nextToken();
        String skip_me = st.nextToken();
        String in_out = st.nextToken();

        //    Rebuild the string...
        si = first_name.trim() + " " + last_name.trim() + " is ";

        if ( in_out.equals( "in" ) )
        {
            si += "out";
            newInOut = "N";
        }
        else
        {
            si += "in";
            newInOut = "Y";
        }

        try
        {
            //    Try and save it...
            String sql = "update emp set in_out_ind = '" + newInOut + "' " +
                "where emp_id = " +
                ( ( EmployeeRecord )rowMap.elementAt( idx ) ).emp_id;

            getConnector().getStatement().executeUpdate( sql );

            String statStr = first_name + " " + last_name + " has been marked ";

            if ( newInOut.equals( "Y" ) )
                statStr += "in";
            else
                statStr += "out";

            showStatus( statStr );
        }
        catch ( SQLException e )
        {
            errorLog( "Error during save: " + e.toString() );
            showStatus( "Error during save: " + e.toString() );
            return( false );
        }

        //    Replace the visual...
        theList.replaceItem( si, idx );

        //    Reselect...
        theList.select( idx );

        //    I handled it!
        return( true );
    }

The toggleListItem() method is unique because it rebuilds the current string and replaces it in the list. After the user selects an employee, this method strips the displayed line down to its components. It removes the "In" or "Out" from the end of the line and appends the toggled equivalent. The result is stored in the database.

Only after a successful save to the database is the string replaced in the list, showing the new status.

A Refresh Timer

The last user interface piece that you need to create is the refresh timer. This little guy is responsible for going out and refreshing the list of employees.

The refresh timer is necessary because your target users might have this running at all times. Other employees will utilize this and its underlying database. If it is never refreshed, it would show only the employee's status that the user toggled and the initial values loaded. Using a refresh, however, you can keep your data up-to-date!

First, create an EventTimer to be your refresh timer. If you remember back in Chapter 8, "Utility Classes," the EventTimer is ideal for adding to programs where the underlying interface cannot or should not be changed. This is a case of that. You don't want to change the in-terface of your derived class. It could end up causing other problems down the road, not to mention other people may be using this class. You don't want to change things on them. The use of this EventTimer is perfect.

Creating your timer is a matter of using the new operator:
        //    Get the refresh rate from the configuration file...
        int refreshRate =
            Integer.parseInt( getParameter( "refresh.rate", "60000" ) );

        //    Create a timer to refresh...
        myTimer = new EventTimer( this, refreshRate );

You also query your configuration properties list for a refresh.rate property. If it isn't there, you default to a one minute default refresh rate. Otherwise the refresh rate is used.

Caution
Remember, the refresh.rate configuration parameter should hold values that specify the number of milliseconds between time-outs. Be careful what you place in there.

Finally, when a timer event does occur, you refresh your list:

        //    Did my timer fire?
        if ( myTimer == arg )
        {
            showStatus( "Refreshing..." );

            //    Reload the panel...
            loadPanel();

            showStatus( "Refreshed!" );

            return( true );
        }

Programming Considerations

Aside from the database access, this application is one of the simplest in your intranet application suite. It does nothing more than toggle a single column from Y to N, then back again.

This application presented you with very little challenge. You needed to present an intuitive interface to the user, while making it quick and easy to use. You did this by using the List class.

To recap, this application introduced the following Java intranet programming topics:

Summary

This chapter introduced you to the fourth sample application in your intranet application suite: the Online In/Out Board. This program is only responsible for updating a single column in the employee table. This program will be useful for any employee who needs to know the whereabouts of another employee. Likely uses will be for receptionists who take messages for individuals.

In Chapter 17, "Online Employee Phonebook," you will design and create an Employee Phonebook application. This program allows employees to look at the phone numbers of their coworkers.