*******************************************************************************
*
*  CONTACT  Sample Application
*
*******************************************************************************

These are important instructions to help you get the best and quickest look!

This demo was written using InterBase Objects. 
Please follw Delphi's instructions for installing components.
Be sure to have the evaluation components installed before loading this into Delphi.

--------------------------------------------------------------------------------
INSTALLING IB OBJECTS
--------------------------------------------------------------------------------

In Delphi 2.0 there are only two units that need to be registered.
They are IB_Registration.dcu and IB_Editors.dcu.

In Delphi 3 you need only open, build and install the package IB_Objects.DPK.
There may also be a need to supply the path in the project settings
to where the DCU files will be kept too.
Otherwise, when you go to compile a file not found error may be generated.

--------------------------------------------------------------------------------
IB_WISQL.EXE
--------------------------------------------------------------------------------

Also, you will need to compile a working version of IB_WISQL.EXE.
After installing the components load up the IB_WISQL.DPR and build an EXE to use.
This will be necessary in order to create the GDB file from a script of DDL.

--------------------------------------------------------------------------------
GETTING STARTED
--------------------------------------------------------------------------------

If you have any trouble please email me immediatly at jwharton@mail.sosaz.com
These instructions are very brief but each step is important.
Perhaps printing this out and crossing off each step as you go will be best.

The first thing that needs to be done is to open CONTACT.SQL and alter the path
where the sample GDB file will be created. The path must exist or your IB server
will not be able to create the GDB file.

Once the directory is valid, load this SQL script into IB_WISQL. There is a "Load"
button in the "Script" tab. Execute it and then check the SQL monitor under the 
"Monitor" tab. You should be able to see a trace of the execution of the commands.
If all was well the SQLCODE value should be 0.

After running the script there should still be a connection in place. Look at the
form's caption to see if the database filename is noted. Go to the "Extract" tab
and browse through all of the tabs to get a look at what is in this sample database.

Go ahead and load up the project "Contact" into Delphi. 
Go to the Module_Contact/dmContact data module. Select the cnContact component.
Put your path to the new GDB file in the Database property. Set "Connected" to 
true in the Obj Inspector. 

If you get a connection then you can go to the Code panel and modify where there 
is some code specifying a registry entry. 

This feature makes it so that this can be set to point to a different path without 
having to re-compile the EXE. Skip this if you created the default directory.

After getting the database path stuff finished you can attempt to compile and run it.
You should be prompted with a login dialog if all is well. There are 9 accounts set
up in the database by default. They are MGR1,MGR2,MGR3, USR[1-3],PUB[1-3]. 
The passwords are the same as the user ID. Enter: "MGR1" and "MGR1" and press OK.

You should then get a form with a bunch of blue fields. This is initialized in
search mode. 

At present there are no records entered into the Contact table. 
We need to enter in some now.

Locate the green plus sign on a toolbar on the top of the form and press it. 
This will initiate a record insert to add data to this table.
Fill in the data fields that are green. 
When done, press the green check mark to post your insert. 
This is also a button on the toolbar at the top of the screen.

Hopefully, you entered valid data. If you get an error, 
try to fix it and post again or cancel with the green X button on the toolbar
and use your expert programming skills to find out why there is a 
problem. 

Go back to IB_WISQL an look at domain check constraints, NULLability of columns, etc.
This will be that table named CONTACT that a record will be inserting into.

When you get the hang of inserting enter about 3 or 4 records at least. 
Click on the Count or SUM "sigma" button. This gives a count of how many records 
there are. 

When in search mode this gives a count of how many records match the 
current search criteria. 

Lets look at how we can browse records now.

Click on the "Last" VCR style button on the toolbar for record navigation 
in order to put all records you have inserted into the browse grid.
Try double clicking on one of them and then notice that the selected record
becomes the current record in the data entry fields. Go back to the "Browse" tab
and double-click on another record. It then becomes the current record.
This browse grid acts as a buffer for whatever set of records you are working with.
It is ideal when working with a smaller set of records selected from a table of many.
Smaller sets of records are retrieved by using the built-in searching functionality.

Now let's try searching for one of the records entered. 
Start out real easy, click on the Search button (upper left)
and make the fields go blue again. Then, enter in an ID number that was able to be
posted in the ID field. Try 1000, then 1001, etc.
( They started at 1000 and go up by one for each insert. )
Internal note: See GeneratorLinks property of crContact in dmContact.

You may try browsing the data to find some info to search on if you have forgotton any.

Click on count "sigma" and there should be a single record found. 
You can clear the search by clicking on the Blue X when in search mode.
This will make all records visible again when counted or selected.

Use the navigation buttons to navigate the dataset. 
Notice that there is no PRIOR button. This is because InterBase uses unidirectional 
cursors. There is no built in buffering in the IB_DataSet component. YET! 
At this point you are working directly with the server.
If you click on the Last button it grabs all of the records ( that meet the search 
if any ) and puts them into a browse grid. This is a basic buffer.

It only fetches records that meet whatever search criteria has been entered.

In the grid you can double-click on a record and it is pulled up so that it can be
updated. Try double clicking on one and then go back to the grid and double click on 
another one. The grid is not reset until the next time Last is clicked on again.

Once you pull up a record you can simply edit it. As soon as a change is made the 
fields go to yellow. This denotes Update mode. Again, the yellow Check or X button 
will save or cancel the changes made.

Also note that this application is set to use AutoCommit to true. This means that
every time something is posted there is a SavePoint generated which is a commit
but the current transaction is retained. This allows one to stay in the current
cursor that is open. Update and post a record and then look in the Monitor tab to
see the TRANSACTION SAVEPOINT entry. This is from dmContact.trContact.AutoCommit.
Set AutoCommit to false and add a TransactionBar component to the MainForm. 
Point it at the trContact component. This would then allow the user to control
when their work is saved or not. <Not recommended in most applications.>

If a name or phone number is changed then there are triggers set up on the server
to produce a history record. This is so that this information will always stay on
the system and not be lost. Change a name or phone (not business phone) and then 
go to the History tab. You should see a record with the previous values. These are
read only.

When in search mode go to the history tab. The grid is gone! In its place are data
entry fields. These fields are here to allow the history items to be searched on.
If you had a freind's phone memorized very well but it recently changed to a new one
you could pull up your friend's record by putting their old telephone number in
the phone field of the history tab when in search mode. Click COUNT or FIRST to see
if the record with the old phone number comes up.

After having tried this scenario take a look in the Monitor tab to see the SQL
statement that is created for you in order to perform this search. 
It should be somewhere right at the bottom.
Wow! A nested select! There is some pretty sophisticated stuff built into IB Objects.
It took no application code at all to do this!

The monitor tab is an excellent way for you to get an idea of what is going on behind
the scenes. Take a browse through there whenever to see what is going on. Especially
when you have some complicated searches see what SQL statements are put in place for
you.

The red UP ARROW button allows a different order to be put in place.
Look at the dmContact.crContact.OrderingItems... properties. This allows a quick and
easy way to provide different selection orders for the data.

In the File menu there is a seting to "Refresh" this simply ENDS the transaction, 
disconnects from the database, reconnects, starts new trans and goes to search mode.
This is essentially that same as going out and back in to the application. For 
example, if the server crashes then try a refresh when it is back up. It should work.

In the User Settings menu option, a MGR type login can add/del/upd other users 
as necessary. A USR can only modify their own account's settings. 
A PUB account cannot even get this menu option. By default they can only do searches.

Other properties of intrest could be dmContact.crContact.DisplayNames. This is how the
grids have more human readable column headings. See also crHistory.DisplayNames.
Notice also the various Hint... properties. These are reflected on the NavigationBar
as well as the other corresponding bars.

If Last is selected you may notice a dialog appear. This is a fetch callback mechanism.
It allows the user to tell it to stop fetching rows of data. This is very handy if the
user is sitting on a table of 1 million records and hasn't entered any search criteria.
Dumb computers just say "OK, I'll fetch that!" Chug, Chug, Chug.... Not knowing that
to fetch one million records could take a little while. Not to mention that if the
fetched data is going into a browse grid that the memory would go to the ceiling long
before the query would complete. Try doing this with the BDE! The callback increment
can be custimized as well as the actions taken. You get a callback for the INIT, a
refresh per each increment, and a FINAL callback when all rows have been selected or
it has been aborted.

-------------------------------------------------------------------------------------

OK, after you get a good idea of what this application does begin to look more deeply
through the code to see what all is required in the application to make all of this work.

Be sure to view the forms and data modules as text. Especially look at the crContact
components DFM values.

Sorry that there are not very many comments in the code. I don't generally like to
use comments. I try to just write code that is easily understood. Of course that
doesn't mean that it is. <g>

If you have any questions about this application please contact me via e-mail at:

jwharton@mail.sosaz.com


Thank you very much for getting this far!