08 Menu
08 Menu
08 Menu
Interviewer Menu
List households
Interview households Summary Report
Logout
Household Data
Entry Program
We will keep the default id-item that CSPro creates for us. The menu program dictionary doesn’t
really need an id-item since we do not need to save our menu choices to the data file. However,
CSPro requires that we have at least one id-item so we will keep it.
Create the items in the dictionary and then create a form and drop the items onto the form. Do
not drop the id-item onto the form. Unlike typical data entry applications, menu programs tend
PROC LOGIN
If the user selects to login as an interviewer we skip to the interviewer main field to show the
interviewer menu, otherwise we skip to the supervisor main menu field to show the supervisor
menu.
Handling the interviewer menu is similar. Here we will create user defined functions to launch
the listing and household programs.
PROC INTERVIEWER_MAIN_MENU
postproc
It is important to make sure that after the postproc of the menu field we do not let CSEntry
continue to the next field, otherwise after the interviewer launches the household listing they
would end up in the next field, which, in this case is the supervisor menu. To prevent this, we put
a reenter at the end of the postproc so that we go back into the same menu field again.
PROC SUPERVISOR_MAIN_MENU
function launchHouseholdDataEntry()
execpff("../Household/Popstan2020.pff", stop);
end;
This will start the data entry application and immediately exit the menu. The “..” in the path to
Popstan2020.pff tells CSEntry to go one directory up, i.e. to go to the parent of the Menu
directory and from there to Household/Popstan2020.pff.
PROC POPSTAN2020_QUEST
We also need to handle the case where the interviewer uses the stop button on Windows or the
back button on Android to exit the data entry application. To do this we provide an OnStop
function in the entry application logic that relaunches the menu program. OnStop is a special
function. If CSPro finds a function named OnStop in your logic it will call it when the
interviewer pushes the stop button (or the back button on Android).
function OnStop()
execpff("../Menu/Menu.pff", stop);
end;
PROC INTERVIEWER_MAIN_MENU
postproc
In the onfocus proc for CHOOSE_HOUSEHOLD we need to loop through every case in the
listing file. We can use a different form of the loadcase statement to do this. If you call loadcase
with no id-items, it will load the next case in the file. If there are no more cases in the file, it
returns 0. Before we do this we need to move to the start of the file which can be done using the
locate statement. Locate takes an operator (=, <, >, <=, >=) and a case-id string and moves to the
locate(MY_DICT,>=,"");
while loadcase(MY_DICT) do
// Do something with case
enddo;
We will use this pattern in the onfocus of CHOOSE_HOUSEHOLD to build the value set from
the listing file:
PROC CHOOSE_HOUSEHOLD
onfocus
numeric nextEntry = 1;
nextEntry = nextEntry + 1;
enddo;
close(LISTING_DICT);
When we run this we should see a list of the households in the listing file as the value set for
CHOOSE_HOUSEHOLD.
if setfile(pffFile,pffFilename,create) = 0 then
errmsg("Failed to open file %s", pffFilename);
endif;
filewrite(pffFile,"[Run Information]");
filewrite(pffFile,"Version=CSPro 7.0");
filewrite(pffFile,"AppType=Entry");
filewrite(pffFile,"[DataEntryInit]");
filewrite(pffFile,"[Files]");
filewrite(pffFile,"Application=" + pathname(Application) +
"../Household/Popstan2020.ent");
filewrite(pffFile,"InputData=" + pathname(Application) +
"../Data/Popstan2020.csdb");
filewrite(pffFile,"[ExternalFiles]");
filewrite(pffFile,"DISTRICTSPERPROVINCE_DICT=" + pathname(Application) +
"../Household/Resources/DistrictsPerProvince.dat");
filewrite(pffFile,"DISTRICTS_DICT=" + pathname(Application) +
"../Household/Resources/Districts.dat");
filewrite(pffFile,"ENUMERATIONAREAS_DICT=" + pathname(Application) +
"../Household/Resources/EnumerationAreas.dat");
filewrite(pffFile,"HOUSEHOLDPOSSESSIONVALUE_DICT=" +
pathname(Application) +
"../Household/Resources/HouseholdPossessionValues.dat");
filewrite(pffFile,"[UserFiles]");
filewrite(pffFile,"TEMPFILE=%s","");
filewrite(pffFile,"[Parameters]");
filewrite(pffFile,"PROVINCE=%s", CHOOSE_HOUSEHOLD[1:1]);
filewrite(pffFile,"DISTRICT=%s", CHOOSE_HOUSEHOLD[2:2]);
filewrite(pffFile,"ENUMERATION_AREA=%s", CHOOSE_HOUSEHOLD[4:3]);
filewrite(pffFile,"AREA_TYPE=%s", CHOOSE_HOUSEHOLD[7:1]);
filewrite(pffFile,"HOUSEHOLD_NUMBER=%s", CHOOSE_HOUSEHOLD[8:3]);
close(pffFile);
execpff(pffFilename, stop);
end;
PROC PROVINCE
preproc
We use an if statement to only fill in the field if the pff file actually has a value for the parameter.
This way we can still easily test our application without using the menu program. We should also
make the field protected if we are filling it in. We can do this using the set attributes protect
command.
PROC PROVINCE
preproc
endif;
if setfile(pffFile,pffFilename,create) = 0 then
errmsg("Failed to open file %s", pffFilename);
endif;
filewrite(pffFile,"[Run Information]");
filewrite(pffFile,"Version=CSPro 7.0");
filewrite(pffFile,"AppType=Entry");
filewrite(pffFile,"[DataEntryInit]");
// Use modify mode if the case already exists in the household
// data file, otherwise use add mode.
string mode;
open(POPSTAN2020_DICT);
if loadcase(POPSTAN2020_DICT, CHOOSE_HOUSEHOLD) = 1 then
mode = "modify";
else
mode = "add";
endif;
close(POPSTAN2020_DICT);
filewrite(pffFile,"StartMode=%s;%s",mode, CHOOSE_HOUSEHOLD);
filewrite(pffFile,"[Files]");
filewrite(pffFile,"Application=" + pathname(Application) +
"../Household/Popstan2020.ent");
filewrite(pffFile,"InputData=" + pathname(Application) +
"../Data/Popstan2020.csdb");
filewrite(pffFile,"[ExternalFiles]");
filewrite(pffFile,"DISTRICTSPERPROVINCE_DICT=" + pathname(Application) +
"../Household/Resources/DistrictsPerProvince.dat");
filewrite(pffFile,"DISTRICTS_DICT=" + pathname(Application) +
"../Household/Resources/Districts.dat");
filewrite(pffFile,"ENUMERATIONAREAS_DICT=" + pathname(Application) +
"../Household/Resources/EnumerationAreas.dat");
filewrite(pffFile,"HOUSEHOLDPOSSESSIONVALUE_DICT=" +
pathname(Application) +
"../Household/Resources/HouseholdPossessionValues.dat");
filewrite(pffFile,"[UserFiles]");
filewrite(pffFile,"TEMPFILE=%s","");
filewrite(pffFile,"[Parameters]");
filewrite(pffFile,"PROVINCE=%s", CHOOSE_HOUSEHOLD[1:1]);
filewrite(pffFile,"DISTRICT=%s", CHOOSE_HOUSEHOLD[2:2]);
filewrite(pffFile,"ENUMERATION_AREA=%s", CHOOSE_HOUSEHOLD[4:3]);
filewrite(pffFile,"AREA_TYPE=%s", CHOOSE_HOUSEHOLD[7:1]);
filewrite(pffFile,"HOUSEHOLD_NUMBER=%s", CHOOSE_HOUSEHOLD[8:3]);
execpff(pffFilename, stop);
end;
Role
(1=interviewer,
Staff code Name 2=supervisor) Province District EA
001 Shemika Rothenberger 2 1 1
002 Andrew Benninger 1 1 1 1
003 Angelica Swenson 1 1 1 2
004 Zelma Hawke 1 1 1 3
005 Willis Catron 1 1 1 4
Note that for the supervisor we leave the enumeration area blank since they are assigned to an
entire district and not to an enumeration area. The supervisor will supervise all of the
enumerators in their district.
Let’s create a new external dictionary in the menu program for this file and use Excel2CSPro to
convert the spreadsheet to a data file named staff.dat. Create a resource directory for the menu
program and put staff.dat into the resource directory.
Let’s modify the login field so that the user enters the staff code instead of picking the role. We
will need to increase the size of the field and delete value set. In the postproc we now need to
look up the staff code in the staff file, validate it, and then skip to the appropriate menu based on
the role.
PROC LOGIN
PROC LOGIN
postproc
// Verify staff code using lookup file
if loadcase(STAFF_DICT, LOGIN) = 0 then
errmsg("Invalid staff code. Try again.");
reenter;
endif;
Settings are always stored as alphanumeric so we need to use maketext to convert the numeric
LOGIN code to a string.
In the preproc we will try to retrieve the login code from the settings and if it is not empty we
will use it instead of asking the user to enter the code.
PROC LOGIN
preproc
// Check to see if there is an existing login code
// use that
if loadsetting("login") <> "" then
LOGIN = tonumber(loadsetting("login"));
noinput;
endif;
PROC INTERVIEWER_MAIN_MENU
postproc
Completion Report
-----------------
Province: 01 District: 01
Interview Status
----------------
Completed: 10
Non-contact: 1
Vacant: 2
Refused: 1
Partially complete: 5
Total: 19
To generate this report, we need to loop through all the cases in the household dictionary and
count the number of cases with each interview status. We can use the locate/loadcase pattern to
do this. To compute the totals for each category we create a local variable for each status and
increment the appropriate variable every time we encounter a household with that status.
numeric complete = 0;
numeric nonContact = 0;
numeric vacant = 0;
numeric refused = 0;
numeric partial = 0;
if INTERVIEW_STATUS = 1 then
complete = complete + 1;
elseif INTERVIEW_STATUS = 2 then
nonContact = nonContact + 1;
elseif INTERVIEW_STATUS = 3 then
vacant = vacant + 1;
elseif INTERVIEW_STATUS = 4 then
refused = refused + 1;
else
partial = partial + 1;
endif;
enddo;
close(tempFile);
if getos() in 20:29 then
// Android - use "view:"
execsystem(maketext("view:%s", reportFilename));
else
// Windows - use "explorer.exe <filename>"
execsystem(maketext("explorer.exe %s", reportFilename));
endif;
end;
Province: 01 District: 02
Male: 1020
Female: 1025
Total: 2045