Tasmanian Traders Sample

The Tasmanian Traders sample is an example of an integrated Visual FoxPro application. The application is an order entry system for a fictional import and export company that sells specialty foods from around the world.

Tasmanian Traders provides order entry functionality, allowing users to:

The application also illustrates user-level security by requiring users to log onto the application before seeing or editing data.

Each step in the development of the Tasmanian Traders application has been documented as follows:

To run Tasmanian Traders

  1. From the Program menu, choose Do.

  2. Choose the …\Samples\Vfp98\Tastrade folder.

  3. Double-click Tastrade.app.

To open the project for the Tasmanian Traders application in the Project Manager

Creating the Specification for Tasmanian Traders

Before any code was written for Tasmanian Traders, a specification detailing the system requirements, functionality, and appearance was written, revised, and refined. The specification is over 30 pages long and includes the following required elements.

Functionality

The application provides order entry functionality, which must include features that allow users to create new orders; add items to orders directly or select items from previous orders; and calculate line item extensions, subtotals, and order totals adjusted for discounts and freight. The application must provide security by requiring users to log onto the application before seeing or editing data.

Excluded Functionality

The application will not manage accounts receivable, billing, or inventory.

Interface Requirements

The interface must meet Windows standards. It should be as attractive and intuitive as possible. These subjective interface requirements were difficult to specify in detail. Consequently, they underwent quite a few changes through the development cycle.

International Requirements

Because the application will be localized into multiple languages, coding must conform to standards required by the internal localization tools.

Visual FoxPro Features

As a sample, the application must illustrate many of the new features of Visual FoxPro, demonstrate how to coordinate menus and toolbars, and provide sample reports.

System Requirements

The application must run with the minimum processor and memory requirements that Visual FoxPro requires, and in a screen display of 640 x 480 pixels.

In refining the specification, prototypes of the main forms in the application were developed quickly, without functional code. These prototypes were used to demonstrate several usage scenarios to clients. Client feedback about the interface and the functionality was then incorporated into the specification.

As development progressed, client feedback was incorporated directly into the application without being added to the specification document first. The finished Tasmanian Traders application is noticeably different from the application described in the original specification.

Designing the Tastrade Database

The key tasks in designing the database were:

Creating Table Structures and Relationships

The process of creating table structures and relationships in Tastrade is discussed in Chapter 5, Designing Databases, in the Visual FoxPro Programmer's Guide. To see the tables and relationships in the Tastrade database, open the Database Designer.

Because the central entity in this application is an order, the table involved in the most relationships is the Orders table. Other entities directly or indirectly support an order:

Two tables, Suppliers and Category, support the Products table although they do not directly supply information for an order. Suppliers are the source of the products while the Category table provides information that can be used to manage the products. In Tasmanian Traders, these entities aren't very significant. In other applications, for example, an inventory management application, they would be.

In addition to the logical design of the database, security and data integrity are important when creating the database.

Implementing Security

Database security involves restricting access to data. Unauthorized users should not have access to any data while other users should not have full access to certain data. For example, you might not want order-entry personnel to be able to change employee information or customer credit limits.

To implement security, two fields were added to the Employee table: Group_ID and Password. To gain access to information in the database, a user must complete a login form and supply the appropriate password. When the user logs in, Tasmanian Traders can determine the access level of that user from the value in the Group_ID field.

Because a login form is a common element in many applications, a class was created for the login form: Login in Login.vcx. This form class contains text boxes for a user to enter a user ID and a password. Properties of the class are used to specify the table and the field for the password. Generic code is called in the Click event of the OK command button to validate the password the user entered. A property of the form (uRetVal) is set on whether a user entered the right password.

For this application, a subclass, LoginPicture, was created for the Login class. LoginPicture includes all the functionality of the Login class, plus a picture of the user, a text description of the user, and a hint for the password. None of these objects would be desirable in a login form outside the context of Tasmanian Traders.

A login form provides a level of security in a stand-alone application, but because any user with a copy of Visual FoxPro can open the database and view or change data outside of the application, the data isn't really very secure. In a real-world context, network security and/or data encryption would be used to increase security. In the world of this sample application, however, all Visual FoxPro users should have access to the data from inside or outside the application. Therefore, the login user names and passwords need to be apparent to anybody logging in to the application, and the data is not encrypted by the application.

Maintaining Data Integrity

Protecting data integrity involves making sure that authorized users don't add, change, or delete data that would make parts of the database invalid or inaccurate.

Data integrity management at the database level applies whether a user is changing values through the forms in the application or directly in a Browse window. Thus, data integrity, in the form of referential integrity and enforcing business rules, is handled in the database.

Referential Integrity

Referential integrity was implemented at the database level using the Referential Integrity Builder. For all parent tables in the database, when a key value is changed, that change is also made in the child tables (Cascade on Updating). When a user deletes a record in a parent table, the associated records in the child tables are also deleted (Cascade on Deleting). Users cannot delete records in other parent tables if there are related records in a child table (Restrict on Deleting). A user cannot insert records into child tables that don't match records in the parent tables (Restrict on Inserting).

Each of the tables in Tastrade (except for Order_Line_Items) has a primary key field. Because Visual FoxPro requires a non-null and not empty value for this field and automatically prevents a duplicate value from being entered in the field, no code has to be written to prevent duplicate primary keys. To make it even easier for a user, however, NewID( ), a stored procedure, generates a new value for the primary keys of most tables. The next primary key value for each appropriate table is stored in the Setup table. NewID returns this value and calculates a new value for the next available key. NewID( ) is the default value (set in the Table Designer) of Orders.Order_id, Products.Product_id, and other primary key fields in the database.

For the Customer table, however, it would not be worth the time and effort to generate new Customer_id values for the user. The user must supply the primary key value for a new record added in the Customer or Add Customer form. The primary key for the Customer table is Customer_id. The naming scheme for customer identification is based on the name of the company. For example, the Customer_id for the B's Beverages company is BSBEV.

Business Rules

The Tastrade database needed a rule to ensure that orders couldn't be saved without at least one associated line item. The stored procedure ValOrder( ) manages this requirement. In addition, ValOrder( ) makes sure that the order total is not above the customer's Max_order_amt or below the customer's Min_order_amt. In Tasmanian Traders, if an order total is above the minimum or maximum order amounts for a customer, a message box gives the user the option to override the rule. In a stricter data scenario, you wouldn't allow a user to override the rule.

ValOrder( ) calls the RemainingCredit( ) and CalcMinOrdAmount( ) stored procedures. Because the database doesn't store information about which orders a customer has or has not paid for, it isn't possible to get information on a customer's outstanding balance. The RemainingCredit( ) procedure assumes that all orders are outstanding.

Form-Level Validation

Form-level data validation includes restricting user access to data by enabling and disabling appropriate controls. Optimistic row buffering is set at the form level for all data-bound forms. The Order Entry form has optimistic table buffering set for the table displayed in the grid. The optimistic row and table buffering is used to revert records when users decide that they don't want to save their changes.

Database Maintenance

To allow a user to reindex the tables and check the validity of the database, the Rebuild form was added to the application. The Rebuild form uses the REINDEX and the VALIDATE DATABASE commands.

As an alternative to using the REINDEX command, you could extract the index expressions using the TAG( ) and KEY( ) functions, delete all the tags with DELETE TAG ALL, and recreate all the indexes using the INDEX ON command. This method would minimize the .cdx file.

Comments on Creating the Database

During development, some of the table names and field names were changed to illustrate the long name capabilities of Visual FoxPro. Consequently, views and indexes had to be recreated, and the ControlSource property of bound controls on forms and reports had to be manually changed.

After login, users originally had to select an action from a menu on an otherwise blank screen. Later in the development process, the Startup_action field in the User_level table was added. Information in this field is used to specify the part of the application that should be run right after login.

There are two free tables (not included in the database) in the Tastrade project: Behindsc and Repolist. Behindsc is the table used to store Behind the Scenes information, which describes how specific functionality in the application was implemented. It does not contain data for use by the application. Repolist is a table listing available reports, along with a descriptive name and a type for each report. These tables are used internally by the application; they do not constitute part of the data stored in the database by the user. Either of them could have been included in the database, but were not because they work independently of the data that is stored in the Tastrade database.

Designing and Creating the Tasmanian Trader Classes

Six class libraries were created for Tasmanian Traders. Most of the Visual FoxPro base classes were subclassed so that the basic "look and feel" of the application could be easily maintained across components. As much generic functionality as possible was included at the class level so that the classes could be easily maintained and reused.

In deciding what classes to create, as much consideration was given to maintenance and future projects as to the current project. The goal was to encapsulate as much generic functionality in classes as possible. As a result, the underlying classes contain a lot of built-in functionality and they are designed to be integrated, but it isn't easy for someone to open the project, look at the components, and understand how the application works. Because the components in Tasmanian Traders are integrated so closely, you can't just take one or two of them, add them to another project that is organized differently, and expect them to work. You can quickly and easily expand Tasmanian Traders, though, or other applications built around the same model, by subclassing the appropriate classes.

Instead of adding the AddNew, Save, Delete, Restore and table navigation methods to the form class, the developers could have created a custom class to hold table operation methods and added an object based on that class to form classes or directly to forms. This would provide more flexibility because the functionality could be added to any form (or even container or control classes) later in the development process, regardless of its parent class. On the other hand, this would provide an additional layer of reference whenever the methods were called and, if the custom class were contained in a different .vcx file, another file would have to be opened when the forms opened. Because the class structure was clearly delineated before the forms were created and all forms bound to data were to inherit from tsBaseForm, the methods were included in tsBaseForm.

In Tasmanian Traders, a toolbar provides user access to functionality that is common to all forms. An alternative would be to create a class of command buttons to provide this functionality and add an object based on the class to each form. The advantage of this would be that the user might more easily associate the buttons with the form, and a user could more easily access the command buttons with the keyboard. On the other hand, Microsoft Office standards call for toolbars, so users are familiar with them. More importantly, the toolbar didn't take up any additional space on the forms and didn't add any additional controls on forms that already had quite a few controls. Additionally, the toolbar can be customized more easily at run time based on the access level of the user.

The environment settings were saved in a class so they could be set and restored in a single operation. Another benefit of saving environment settings in a class and restoring them in the code associated with the Destroy event is the fact that it is easy to recover when crashes occur in testing. Issuing RELEASE ALL causes the object Destroy events to fire, restoring the original environment settings.

Writing, Testing, and Debugging Tasmanian Traders

Code in the stored procedures in the database, class methods, form methods, menus, and programs was tested and debugged as it was being written.

This topic covers writing, testing, and debugging the Tastrade application in the following areas:

This topic also provides a synopsis of what happens when the Main Program is initially executed. At the end of the topic, there are additional Comments about the Code.

Forms

Tastrade includes Form classes (stored in .vcx files) and forms (stored in .scx files) based on Form classes. See the section on Designing and Creating the Tasmanian Trader Classes for information about Form classes. The following list includes all the forms (.scx files) in Tasmanian Traders [ParentClass listed in brackets].

Form Name Description
BehindSc.scx [tsBaseForm] Behind the Scenes form.
ViewCode [tsTextForm] Displays the code from Behind the Scenes.
Category [tsMaintForm] Maintenance form for Category.dbf.
ChngPswd [tsBaseForm] Allows user to change password.
CustAdd [tsBaseForm] Allows user to enter information for a new customer.
Customer [tsMaintForm] Maintenance form for Customer.dbf.
Employee [tsMaintForm] Maintenance form for Customer.dbf.
GetInv [form] Allows user to specify a date range in the Orders report.
GetTitle [form] Allows user to filter the employees to be displayed in the ListEmpl report. GetInv and GetTitle are based on the Visual FoxPro base form class so that they can be run in reports launched from Project Manager without having to open libraries.
OrdEntry [OrderEntry] Order Entry form.
OrdHist [OrderEntry] Order History form.
Product [tsMaintForm] Maintenance form for Products.dbf.
Rebuild [tsBaseForm] Allows administrative user to reindex and check validity of the database.
Reports [tsBaseForm] Allows user to specify a report to run.
Shipper [tsMaintForm] Maintenance form for Shipper.dbf.
Supplier [tsMaintForm] Maintenance form for Supplier.dbf.

Most forms with controls that aren't bound to data (for example, IntroForm and About) are saved as classes in .vcx files and created with the CREATEOBJECT( ) function. Sometimes a form that is data-bound is called directly as a class. For example, the Login class exposes properties to set the data for its controls. The default values of these properties are set to Tasmanian Traders tables and fields. The subclass, LoginPicture, is used directly in the application; there is no .scx file for these forms.

The advantage to running a Form class directly is that you can create the form and show it in two separate operations:

If you do this, you can adjust property settings after creating the object but before displaying it.

The advantage of creating a form in the Form Designer is access to a data environment and the properties, events, and methods associated with the data environment object. It is also more convenient to design and test forms in this way because you can run them directly from the Form Designer or from the Project Manager.

Most of the data-bound forms in the application contain tables in their data environments. If the application had included a form that allowed a user to simultaneously update multiple tables, a view would have been created for that purpose.

Reports

Reports can be developed any time after the database is in place. Tasmanian Traders is not a report-intensive application, so the reports were created relatively late in the development process. Each report contains a local view in its data environment. Two of the reports allow the user to specify parameters for the report:

The views in the data environments of these reports were created with parameters. When the report data environments opens the views, Visual FoxPro, by default, presents the user with a generic dialog asking for the parameters. To customize this behavior for Tasmanian Traders, the AutoOpenTables properties of the data environments were set to false (.F.). In the Init of the data environment, custom forms are run to get the parameter variables. Then the OpenTables method of the data environment is called.

Queries were considered as sources for the reports, but weren't used because they would require extra files (.qpr files) to maintain and track. Views, on the other hand, were contained in the database (.dbc) file and can be conveniently displayed and modified in the Database Designer, as well as added directly to the data environment. SQL SELECT statements, however, are used as needed, as in the RemainingCredit stored procedure.

Menus and Toolbars

The main menu in the application is defined in Main.mnx. The single toolbar used in the application is based on the tsToolbar class in Tsbase.vcx.

Cleanup code in the menu checks the user level of the person who has logged in to the application, and releases pads and bars to which the user should not have access. Code in the procedure associated with Return to Visual FoxPro on the File menu calls the Cleanup( ) method of the application object, which issues CLEAR EVENTS and restores the Visual FoxPro menu system.

Code associated with the Click event of buttons on the toolbar calls methods of the active form for functionality. In this way, the functionality associated with a form is encapsulated with the form.

To coordinate the menus and toolbars in the application, code in the menu items calls the Click event code of the command buttons on the toolbars. An expression in the Skip For clause enables or disables the menu items based on the state of the corresponding command button on the toolbar. For a detailed description of coordinating menus and toolbars, search Help for "coordinating toolbars and menus."

Error Handling

The goal for error handling was to anticipate errors and prevent them from appearing in code, if possible. For example, code in Main.prg is included to adjust the relative path setting if Main.prg (in …\Samples\Vfp98\Tastrade\Progs) is run instead of Tastrade.app. Before code in a method sets or reads properties of the application object from outside the object, it first checks to make sure the application object exists:

IF TYPE('oApp') == 'O'
   * do some code
ENDIF

If choosing a control would cause an error in a particular situation, that control is disabled.

Not all errors can be anticipated in code, however. Error handling, when necessary, is managed in the code associated with the Error event of an object.

When an error occurs in method code, Visual FoxPro checks for error handling code associated with the Error event of the object. If no code has been written at the object level for the Error event, the Error event code inherited from the ParentClass, or from another class up the class hierarchy, is executed.

If no code has been written for the Error event anywhere in the class hierarchy, Visual FoxPro checks for an ON ERROR routine. If no ON ERROR routine exists, Visual FoxPro displays the default Visual FoxPro error message. To see the default Visual FoxPro error messages, see Error Messages.

Tasmanian Traders checks for three types of errors that could occur at the database level: field rule violated, primary key violated, and failed trigger. Because the forms in Tasmanian Traders have a BufferMode setting of 2 - Optimistic, the only times these errors could occur are when the user moves to a different record (causing the buffer to be flushed) or saves changes to the current record. Both of these tasks are handled through methods at the form level (inherited methods from tsBaseForm), so Visual FoxPro first checks for error handling code in the Error event of the form. For example, the following code is associated with the Error event of the Customer form:

DO CASE
   CASE nError = 1884  && Primary key violated
   THISFORM.pageframe1.page1.cntCustomerInfo.Error(nError, cMethod, nLine)
   CASE nError = 1582  && Field rule violated
   THISFORM.pageframe1.page1.cntCustomerInfo.Error(nError, cMethod, nLine)
   OTHERWISE
      tsMaintForm::Error(nError, cMethod, nLine)
ENDCASE

If the primary key or a field rule is violated, the error information is passed to the control it relates to, cntCustomerInfo, so that the control's error code can present a more specific error message than the Visual FoxPro default error message, restore old values as appropriate, and set the focus to the appropriate control.

If another error is encountered, the Customer form passes the error to the parent class, tsMaintForm, which inherits error handling code from tsBaseForm. If the error indicates a failed trigger, code associated with the Error event of tsBaseForm displays the corresponding error message stored in the aErrorMsg[ ] property of the Customer form: "Insert trigger failed," "Update trigger failed," or "Delete trigger failed." (A custom error message unique to the each form can be created by initializing the appropriate element of the aErrorMsg[ ] array in the Init of that form.) Any other errors are handled by giving the user the option to Abort, Retry, or Ignore.

There is one ON ERROR setting in Tasmanian Traders in the RestoreWindowPos( ) method of tsBaseForm:

ON ERROR llError = .T.

The code that restores the window postions checks the value of llError. If an error occurs during the reading of the saved window positions from the .INI file, the form's default Top and Left properties determine the form's position.

Testing and Debugging

Testing and debugging was an integral part of all the implementation stages of the development process. As soon as any of the components in Tasmanian Traders were somewhat functional, they were tested. As soon as any bugs were encountered, they were isolated using the Visual FoxPro debugging tools and fixed.

An application-level constant defined in Tastrade.h was used in the development of Tasmanian Traders to facilitate testing and debugging:

#DEFINE DEBUGMODE .T.

Conditional code automatically logged any user in as the Applications Developer (Leverling) if DEBUGMODE is True (.T.) so that the developers didn't have to go through that process every time they ran the application to test it.

The Utilities menu of the main Tasmanian Traders menu bar is active when a user, or a tester, logs in as an Applications Developer. This menu provides access to the Trace, View, and Debug windows, as well as the ability to cancel, resume, and suspend code.

The Main Program

Code in Main.prg is the main program of the application. When you run the application, the code in Main.prg is executed first. This code:

The following actions occur as a result of this object creation:

  1. The Init event of the parent class (APPLICATION) is invoked. Code associated with this event creates an environment object and saves other environment settings:

    THIS.AddObject("oEnvironment", "Environment")

    THIS.oEnvironment.Set( )

  2. The default section of the Tastrade.ini file is read with GetPrivString to determine if the Introductory Screen should be displayed.

  3. If specified in the .INI, IntroForm (Introductory Screen) is displayed.

  4. The Login( ) method of the class is called in the Init event of Tastrade.

  5. The Login( ) method calls the DoFormRetVal( ) method of the class.

  6. DoFormRetVal( ) takes the parameter from Login and creates and shows an instance of the LogInPicture class.

  7. When the user logs in, the user's access level is returned and stored as a property, cUserLevel, of the application object.

  8. Calls the Do( ) method of the application object:
    oApp.Do( )
    

Code in the Do( ) method performs the following actions:

  1. Runs the menu program for the application:
    THIS.DoMenu( )
    
  2. Determines, based initially on the user's access level, the component of the application to run:
    lcAction = THIS.GetStartupAction( )
    * The GetStartupAction method returns
    * the value in the Action field of the User
    
  3. Runs that component, for example Order Entry:
    IF !EMPTY(lcAction)
    &lcAction
    ENDIF
    
  4. Establishes the event wait state with READ EVENTS.

Comments about the Code

For localization purposes, all strings that will be translated into different languages have to be defined with the #DEFINE preprocessor directive. The defined constants have to end in _LOC so that localization tools can identify them for translation. These are defined in the include file Strings.h.

Most of the code in the application is written in class or form methods so that it can be encapsulated with the appropriate objects. Stored procedures allow code specifically used in data maintenance or validation to be stored in the database.

UTILITY.prg, the procedure library for the application, includes four functions:

One could create a class to hold these utilities, but an object created just to provide access to these procedures adds an unnecessary level of abstraction.

Tasmanian Traders Class Libraries

Six class libraries were created for Tasmanian Traders. Some of the key decisions in developing Tasmanian Traders concerned the level at which certain functionality should be incorporated:

Tastrade Sample: Application Class Functionality

A generic Application class, Application, was created in Tsgen.vcx with functionality generic to most applications. This class provides the following functionality:

A subclass of the Application class, Tastrade, in Main.vcx provides additional functionality specific to Tasmanian Traders:

An object, oApp, is created in Main.prg from the Tastrade class.

The following sections list and describe the Application class functionality. 

Save the Visual FoxPro Environment

The Application Class saves the Visual FoxPro environment when the application runs.  The Visual FoxPro environment includes SET command settings such as PATH, TALK, CARRY, and so on. In the Init event of the Application class, code adds a new object to Application based on the Environment class in Tsgen.vcx. In the Init event of the Environment class, code stores the existing Visual FoxPro environment settings to properties of the class so that they can be restored later.

Code associated with the Init event also stores the caption of the main Visual FoxPro window to the cOldWindCaption property of the Application class. These stored settings are restored when an object based on the Application class is released.

Another environment factor in Visual FoxPro is the standard toolbars that are active when an application is run. The Application method ReleaseToolbars( ) stores the names of system toolbars as well as information about whether they were open or closed when the application was run.

Code associated with the Init event of the Application class also pushes the current system menu onto the menu stack so that it can be restored later.

Set Up the Environment

Other code in the Init event of the Application class establishes the run-time environment. This code:

Restore the Original Visual FoxPro Environment

When the application quits, code in the Cleanup( ) method of the Application class restores the original caption of the main Visual FoxPro window, closes the database, clears windows, issues CLEAR EVENTS, restores the initial menu, and calls the ShowToolbars( ) method to reopen the Visual FoxPro system toolbars that were displayed before Tastrade.app was run.

When CLEAR EVENTS is issued, program execution continues beyond the READ EVENTS command and code in Main.prg releases oApp. When the Application object is released, the Destroy event of the Environment class occurs because it is a member of the Application class.

In the Destroy event of the Environment object, the Reset( ) method of the Environment object is called to restore the Visual FoxPro environment settings that were in effect when the Environment object was created.

Run the Main Menu and Establish the Event Loop

Additional code in the Application object runs the main menu associated with the application and establishes the event loop. The Do( ) method of the Application class is called in Main.prg as soon as the Application object is created. The Do( ) method runs the main menu program and issues READ EVENTS.

Manage Application Toolbars

The Application object also keeps track of application toolbars. A property at the form level indicates the toolbar to be associated with each form. Because there is only one toolbar in this application, this property setting is the same for all the forms in the application.

Forms in the application call the ShowNavToolbar( ) method of the Application class to display the toolbar. The application knows whether the toolbar already exists and shows it only when necessary, incrementing the nFormInstanceCount property.

The ReleaseNavToolbar( ) method of the application, called in the Destroy event of the forms, decrements the nFormInstanceCount property and removes the toolbar after the last form is released.

Manage the User Login Procedure

Most applications in which security is an issue provide some form of login procedure. To manage this procedure, the Login( ) method of the Application class calls the DoFormRetVal( ) method, passing the class name of the login screen. When the user logs in, a property of the Application class, cUserLevel, stores the user level for that user.

This property is used in the menu cleanup code to remove menu items that shouldn’t be visible to a particular user.

Manage Forms

Except for the forms used in reports to set ranges of values for the reports, the forms in Tasmanian Traders are displayed through methods of the Application class. The DoForm( ) method accepts the name of a form and one parameter that can optionally be passed to the form. The DoFormRetVal( ) method accepts the name of a form class and returns a value specified in the form.

Display the Start Up Screen

The subclass of the Application class, Tastrade, in Main.vcx provides additional functionality specific to Tasmanian Traders. The Init event calls the parent class code in the Application class and, if the start up splash screen should be displayed, calls DoFormRetVal("introform" ).

Run the Initial Component When a User Logs In

The subclass of the Application class, Tastrade, in MAIN.vcx provides additional functionality specific to Tasmanian Traders. Code in the Do( ) method overrides the default behavior of the Do( ) method of the Application class. Code in the Do( ) method calls the GetStartupAction( ) method, which returns the component of the application to run after a user logs in. If a default component is specified for a user, code in the Do( ) method runs this initial component.

Tastrade Sample: Form Class Functionality

Tasmanian Traders includes these types of forms:

The following list depicts the form classes and their hierarchies in Tasmanian Traders.

Form Class Class Library
tsFormRetVal Tsbase.vcx
- IntroForm Tsgen.vcx
- Login Login.vcx
- LoginPicture Login.vcx
- FindCustomer Tsgen.vcx
- FindOrder Tsgen.vcx
tsBaseForm Tsbase.vcx
- tsMaintForm Tsbase.vcx
- tsTextForm Tsbase.vcx
- OrderEntry Orders.vcx
- About About.vcx

Modal Forms

All forms that return a value are derived at some level from tsFormRetVal in Tsbase.vcx. All the data entry form classes are based on tsBaseForm in Tsbase.vcx.

tsFormRetVal prevents access to other components while active.

Property Settings

AutoCenter = .T.
BackColor = Light Gray
BorderStyle = 2-Double wide
FontSize = 8
MaxButton = .F.
MinButton = .F.
WindowType = 1-Modal

Custom Properties

uRetVal: Holds the form's return value. Can be any data type; the "u" prefix stands for "unknown." uRetVal is .T. by default.

To create an instance of a subclass, call Application.DoFormRetVal.

Data Entry Forms

Forms for data entry are based on the tsBaseForm class and are closely integrated with the tsToolbar class. tsBaseForm is the parent class of most forms in the Tasmanian Traders application. It provides the following functionality:

Property Settings

BufferMode = 2-Optimistic

Custom Properties

aerrormsg[3] = An array of error messages. This allows generic error handling code to be written in the parent class and custom error messages to be defined in each subclass. The following default values are defined in the code associated with the Init event of particular forms:
aerrormsg[1] = "Insert trigger failed!"
aerrormsg[2] = "Update trigger failed!"
aerrormsg[3] = "Delete trigger failed!"
cToolBar: Holds the name of the toolbar to run when the form is run.
lAllowEdits: Whether or not the current record can be edited.
lAllowDelete: Whether or not the current record can be deleted.
lAllowNew: Whether or not the user is allowed to add new records

Functionality Associated with Events

Init: 1. Restores the previous window position.
2. Adds the form's caption to the menu.
3. Displays the navigation toolbar.
4. Initializes the custom error message array, aerrormsg[ ].
Activate: 1. Selects the alias specified in the InitialSelectedAlias property of the form's data environment.
2. Refreshes the navigation toolbar.
3. Refreshes the menu.
4. Sets the message of the status bar to the form's Caption property.
Error: Defines generic error handling code for all forms.
Destroy: 1. Removes the form's caption from the menu.
2. Saves the position of the window in the Tastrade.ini file.
QueryUnload: Checks whether data has changed, and prompts the user to save changes if necessary.
Unload: Clears the status bar.

Custom Methods

First: Advances the record pointer to the first record.
Next: Advances the record pointer to the next record.
Prior: Advances the record pointer to the previous record.
Last: Advances the record pointer to the last record.

These four methods all share the following behavior:

Custom Methods

Save: Saves the current record.
Delete: Deletes the current record.
AddNew: Adds a new record.
Restore: Restores original field values (cancels changes).
AddToMenu: Adds the form's caption to the Window menu.
RemoveFromMenu: Removes the form's caption from the Window menu.
AskToSave: Prompts user to save changes, not to save changes, or to cancel the last operation.
DataChanged: Returns .T. if any data on the current form has changed.
WriteBuffer: Code to flush the value of the current control to the record buffer.
RefreshForm: Custom refresh routine.
SaveWindowPos: Writes the Top and Left properties of the form to the application's INI file.
RestoreWindowPos: Reads the Top and Left properties of the form from the application's INI file and sets them.
WaitMode: Changes the mouse cursor to an hourglass for all controls on a form.

Lookup Forms

The FindCustomer and FindOrder forms display the customer and order tables, respectively, in a grid and allow the user to change the index tag. The key value from the selected row is returned to the calling form when the user closes the form.

General Purpose Forms

There are two general purpose forms:

AboutBox Form

AboutBox in About.vcx accepts parameters in its Init event for caption texts and a logo bitmap. This class uses API functions to retrieve information from either the WIN.INI file for Windows 3.x, or the system registry otherwise, to display information about the user's system.

IntroForm

IntroForm in Tsgen.vcx is the initial splash screen. Code associated with the Click event of chkShowAtStartUp in this class writes a value to the Tastrade.ini file to specify whether the splash screen should be displayed in the future when Tasmanian Traders is run.

Tastrade Sample: Control Class Functionality

Most of the Visual FoxPro base control classes were subclassed to provide additional default functionality or a consistent appearance. Whenever groups of controls were needed in more than one place in Tasmanian Traders, a class was created.

Because the application had to run in a 640 x 480 display, the default font of these controls was set to be 8 point rather than 10 point, to save space on the forms.

The control classes are listed below by library.

Tsbase.vcx Class Library

Class Description
ts3dShape The class for shape controls, used mostly for accentuating or enclosing parts of a form
TsComboBox The class for all combo boxes in the application.
TsCommandButton The class for all command buttons in the application.
TsEditBox The class for all edit boxes in the application.
TsGrid The SumColumn method is used to automatically sum a value in a grid column. This class is added to the List page of the page frame in the tsMaintForm class.
TsLabel The class for all labels in the application.
TsListBox The class used for all list boxes in the application.
TsTextBox The class for all text boxes in the application.
OrdTextbox A subclass of tsTextbox which is used in Order Entry and Order History forms.
TsToolBarButton The class for all command buttons that appear on toolbars in the application.

Tsgen.vcx Class Library

Class Description
CustomerInfo Includes labels and text boxes for the following fields in the customer table
DateRange A custom control based on the Visual FoxPro Control base class.
Splitter Used in Behind the Scenes to resize the list of features and the description edit box.
TsMaintForm The class for all maintenance forms in the application.
TsToolBar The class for the toolbar in the application.