The Professor-Student Mixed Form Application
This EQUEL/FORMS application lets the user browse and update information about graduate students who have a specific professor. The program is structured in a master/detail fashion, with the professor being the master entry, and the students the detail entries. The application uses two forms—one to contain general professor information and another for detailed student information.
The program uses the "masterfrm" as the general-level master entry, in which data can only be retrieved and browsed, and the "studentfrm" as the detailed screen, in which specific student information can be updated.
The runtime user enters a name in the pname (professor name) field and then selects the Students menu operation. The operation fills the displayed and hidden columns of the studenttbl table field with detailed information of the students reporting to the named professor. The user can then browse the table field (in read mode), which displays only the names and ages of the students. To request more information about a specific student, select the Zoom menu operation. This operation displays the form "studentfrm." The fields of "studentfrm" are filled with values stored in the hidden columns of "studenttbl." The user can make changes to three fields (sgpa, scomment and sadvisor). If validated, these changes will be written back to the database table (based on the unique student id), and to the table field's data set. This process can be repeated for different professor names.
The following two create statements describe the Professor and Student database tables:
## create student /* Graduate student table */
## (sname = c25, /* Name */
## sage = i1, /* Age */
## sbdate = c25, /* Birth date */
## sgpa = f4, /* Grade point average */
## sidno = i4, /* Unique student number */
## scomment = text(200), /* General comments */
## sadvisor = c25) /* Advisor's name */
## create professor /* Professor table */
## (pname = c25, /* Professor's name */
## pdept = c10) /* Department */
/*
** GLOBAL declaration
** grad student record maps to database table
*/
## struct {
## char sname[26];
## short sage;
## char sbdate[26];
## float sgpa;
## int sidno;
## char scomment[201];
## char sadvisor[26];
## } grad;
/*
** Procedure: DECLARE FORMS
*/
## extern int *masterfrm; /* Compiled forms - UNIX */
## extern int *studentfrm;
/* For VMS, to declare the compiled form use the statements
** 'globalref int *masterfrm;' and 'globalref int *studentfrm;'
*/
/*
** Procedure: MAIN
** Purpose: Start up program and call Master driver.
*/
main()
{
/* Start up Ingres and the FORMS system */
## forms
## message "Initializing Student Administrator . . ."
## ingres personnel
## range of p is professor, s is student
Master();
## clear screen
## endforms
## exit
}
/*
** Procedure: Master
** Purpose: Drive the application, by running "masterfrm", and
** allowing the user to "zoom" into a selected student.
** Parameters:
** None - Uses the global student "grad" record. */
Master()
## {
/* Professor info maps to database table */
## struct {
## char pname[26];
## char pdept[11];
##} prof;
/* Useful forms system information */
## int lastrow; /* Lastrow in table field */
## int istable; /* Is a table field? */
/* Local utility buffers */
## char msgbuf[100]; /* Message buffer */
## char respbuf[256]; /* Response buffer */
## char old_advisor[26]; /* Old advisor before ZOOM */
/* Externally compiled master form - UNIX */
## extern int *masterfrm;
/* For VMS use 'globalref int *masterfrm;' */
## addform masterfrm
/*
** Initialize "studenttbl" with a data set in READ mode.
** Declare hidden columns for all the extra fields that
** the program will display when more information is
** requested about a student. Columns "sname" and "sage"
** are displayed, all other columns are hidden, to be
** used in the student information form.
*/
## inittable #masterfrm studenttbl read
## (sbdate = c25,
## sgpa = float4,
## sidno = integer4,
## scomment = c200,
## sadvisor = c20)
## display #masterfrm update
## initialize
## {
## message "Enter an Advisor name . . ."
## sleep 2
## }
## activate menuitem "Students", FIELD "pname"
## {
/* Load the students of the specified professor */
## getform (prof.pname = pname)
/* If no professor name is given then resume */
if (prof.pname[0] == '\0')
## resume field pname
/*
** Verify that the professor exists. Local error
** handling just prints the message, and continues.
** We assume that each professor has exactly one
** department.
*/
prof.pdept[0] = '\0';
## retrieve (prof.pdept = p.pdept)
## where p.pname = prof.pname
if (prof.pdept[0] == '\0')
{
sprintf(msgbuf,
"No professor with name \"%s\" [RETURN]", prof.pname);
## prompt noecho (msgbuf, respbuf)
## clear field all
## resume field pname
}
/* Fill the department field and load students */
## putform (pdept = prof.pdept)
## redisplay /* Refresh for query */
Load_Students(prof.pname);
## resume field studenttbl
##} /* "Students" */
## activate menuitem "Zoom"
## {
/*
** Confirm that user is on "studenttbl", and that
** the table field is not empty. Collect data from
** the row and zoom for browsing and updating.
*/
## inquire_frs field #masterfrm (istable = table)
if (istable == 0)
{
## prompt noecho
## ("Select from the student table [RETURN]", respbuf)
## resume field studenttbl
}
## inquire_frs table #masterfrm (lastrow = lastrow)
if (lastrow == 0)
{
## prompt noecho ("There are no students [RETURN]", respbuf)
## resume field pname
}
/* Collect all data on student into global record */
## getrow #masterfrm studenttbl
## (grad.sname = sname,
## grad.sage = sage,
## grad.sbdate = sbdate,
## grad.sgpa = sgpa,
## grad.sidno = sidno,
## grad.scomment = scomment,
## grad.sadvisor = sadvisor)
/*
** Display "studentfrm", and if any changes were made
** make the updates to the local table field row.
** Only make updates to the columns corresponding to
** writable fields in "studentfrm". If the student
** changed advisors, then delete this row from the
** display.
*/
strcpy(old_advisor, grad.sadvisor);
if (Student_Info_Changed())
{
if (strcmp(old_advisor, grad.sadvisor) != 0)
## deleterow #masterfrm studenttbl
else
## putrow #masterfrm studenttbl
## (sgpa = grad.sgpa,
## scomment = grad.scomment,
## sadvisor = grad.sadvisor)
}
## } /* "Zoom" */
## activate menuitem "Exit"
## {
## breakdisplay
## } /* "Exit" */
## finalize
## } /* Master */
/*
** Procedure: Load_Students
** Purpose: Given an advisor name, load into the "studenttbl"
** table field all the students who report to the
** professor with that name.
** Parameters:
** advisor - User specified professor name.
** Uses the global student record.
*/
Load_Students(advisor)
## char *advisor;
{
/*
** Clear previous contents of table field. Load the table
** field from the database table based on the advisor name.
** Columns "sname" and "sage" will be displayed, and all
** others will be hidden.
*/
## message "Retrieving Student Information . . ."
## clear field studenttbl
## retrieve
## (grad.sname = s.sname,
## grad.sage = s.sage,
## grad.sbdate = s.sbdate,
## grad.sgpa = s.sgpa,
## grad.sidno = s.sidno,
## grad.scomment = s.scomment,
## grad.sadvisor = s.sadvisor)
## where s.sadvisor = advisor
## {
## loadtable #masterfrm studenttbl
## (sname = grad.sname,
## sage = grad.sage,
## sbdate = grad.sbdate,
## sgpa = grad.sgpa,
## sidno = grad.sidno,
## scomment = grad.scomment,
## sadvisor = grad.sadvisor)
##}
} /* Load_Students */
/*
** Procedure: Student_Info_Changed
** Purpose: Allow the user to zoom into the details of a
** selected student. Some of the data can be updated
** by the user. If any updates were made, then reflect
** these back into the database table. The procedure
** returns TRUE if any changes were made.
** Parameters:
** None - Uses with data in the global "grad" record.
** Returns:
** TRUE/FALSE - Changes were made to the database.
** Sets the global "grad" record with the new data. */
int Student_Info_Changed()
## {
## int changed; /* Changes made to data in form */
## int valid_advisor; /* Valid advisor name ? */
## extern int *studentfrm; /* Compiled form - UNIX */
/* For VMS use 'globalref int *studentfrm;' for the compiled form */
/* Control ADDFORM to only initialize once */
static int loadform = 0;
if (!loadform)
{
## message "Loading Student form . . ."
## addform studentfrm
loadform = 1;
}
## display #studentfrm fill
## initialize
## (sname = grad.sname,
## sage = grad.sage,
## sbdate = grad.sbdate,
## sgpa = grad.sgpa,
## sidno = grad.sidno,
## scomment = grad.scomment,
## sadvisor = grad.sadvisor)
## activate menuitem "Write"
## {
/*
** If changes were made then update the database
** table. Only bother with the fields that are not
** read-only.
*/
## inquire_frs form (changed = change)
if (changed == 1)
{
## validate
## message "Writing changes to database. . ."
## getform
## (grad.sgpa = sgpa,
## grad.scomment = scomment,
## grad.sadvisor = sadvisor)
/* Enforce integrity of professor name */
valid_advisor = 0;
## retrieve (valid_advisor = 1)
## where p.pname = grad.sadvisor
if (valid_advisor == 0)
{
## message "Not a valid advisor name"
## sleep 2
## resume field sadvisor
}
else
{
## replace s (sgpa = grad.sgpa, scomment = grad.scomment,
## sadvisor = grad.sadvisor)
## where s.sidno = grad.sidno
## breakdisplay
}
}
## } /* "Write" */
## activate menuitem "Quit"
## {
/* Quit without submitting changes */
changed = 0;
## breakdisplay
## } /* "Quit" */
## finalize
return (changed == 1);
## } /* Student_Info_Changed */