
Page “Opening”
CARA
Credits
As the Credits window from the program indicates, CARA is the work of several people and has evolved over time. The current version, programmed in ToolBook was designed by Beena Choksi, a Ph.D. candidate in the University of Illinois (College of Education). If you have questions about the theories underlining CARA, you should contact Beena Choksi (b-choksi@uiuc.edu).

CARA owes its database handling capabilities to the GisburneDB ActiveX control (http://www.gisburne.com).

Priorities:
Several colleagues asked why I didn’t just use Access alone for developing the entire system. I felt that ultimate development, which would include more CBT components, made ToolBook a better choice.

Page “Case List”
CARA has two primary mechanisms for accessing case study information:
The image below shows how the case study information is organized and presented for the user. Each case is divided into scenes. The ‘Sean’ case has only three scenes. Notice the bottom right corner of the layout. The user has reached this case and scene by selecting the case directly. The interface reminds the user that the case is being viewed sequentially, shows the current and total scene numbers, and provides a mechanism to allow the user to change scenes. Additional information is available through the interface (see examples below):
Assessment Factor/Skills – the user clicks a factor in the list to view additional text in a popup viewer. (These factors are common across all cases.)
Abstract – each case study has a single abstract, again presented in a popup viewer.
Factor/Skills significant in this scene – selecting one of the factors in this list changes the information displayed in the “and issues to consider with respect to them.” field.
Multimedia components: The system allows for the presentation of a still image in conjunction with a scene and video images in conjunction with a given factor relevant to the scene.

Page “Scene Presentation”

Assessment Factors/Skills Popup Viewer

Abstract popup viewer.
Page “Search”
A user looking for information related to specific risk factors can use the search feature to perform a very restricted search (where all factors selected must be present in a scene) or a very broad one (where the presence of any of the selected factors in a scene meets the requirements). This is the classic Boolean AND search (to restrict the results) versus the Boolean OR search.
The user clicks as many factors as desired (these are all multi-select list boxes), then clicks the appropriate ‘Find’ button.
Search results are displayed in a popup viewer (see below). Each line in the single-select list box identifies both a case study and a scene (ex: David 5 = fifth scene of the David case study). When the user selects one of the search results, the program branches back to the same case/scene layout screen we saw earlier. This time, however, the information in the bottom right corner has changed. The user is told: You are viewing SEARCH results. The scene navigation controls now relate to the specific scenes returned by the search – which may be from different cases.
To return to viewing a case sequentially, the user simply clicks the drop down ‘Select Case’ menu and branches to the first scene of the selected case.


Microsoft Access Database
The
database is composed of several tables.
The image below shows the relationships among the key tables.

It is
important that the developers be able to update the access table totally
independently of the front-end; this is done via a standard Access switchboard.

The first
option (Add/Edit Case (and related data)) provides developers with a single
data entry screen, where they can be sure the various components are properly
related.

The
database is set up to also allow developers to view and enter table data
individually and to print reports.
Technical Matters
What must be done for the CARA book to function properly?
Gisburne has made the process simpler to deal with by providing a setup program that you can customize, to install the control, the data access components, and other components as needed, then run your own application setup program.
What happens when the user enters the CARA book?
We perform some standard housekeeping operations – like setting a variable to store the location of the book that has just been opened. The book script contains many of the processing handlers that will allow the user to conduct searches, retrieve and view data. The book script also contains miscellaneous handlers to open and close viewers (like the credits, help).
[key things related to database manipulation]
db
= db("db01") --
Database ActiveX Control
The Scene Presentation page allows us to present the values from specific tables and fields, based on the current case and scene being examined. Look at the code in the Appendix for this page.
The Search page allows the user to select factors and to click the type of search to perform (searchAny or searchAll). These handlers are in the book script.
--------------------------------------------------
--
-- This function is used to return id of the
-- control used for your functions. You can
-- use as many controls as you wish because
-- each is retrieved with it name (CtlName)
--
--------------------------------------------------
to get db CtlName
--------------------------------------------------
return gisburneDB CtlName of page "ActiveX Controls"
end
to handle exit
request "Are you sure you want to quit?" with "Yes" or "No"
if it is "Yes"
forward to system
end
end
to handle menuItemSelected mMenuItem, mAlias
--we have these custom menu options: _Credits, _Search, _Help
conditions
when mAlias = "_Opening"
send showOpening
when mAlias = "_CaseList"
send showCaseList
when mAlias = "_Credits"
send showCredits
when mAlias = "_Cases"
send showCases
when mAlias = "_Search"
send showSearch
when mAlias = "_Help"
send showHelp
when mAlias = "_Copyright"
send showCopyright
else
forward
end conditions
end menuItemSelected
to handle showCredits
in mainwindow
show viewer "credits" as modal
end in
end
to handle showOpening
send closeOtherViewers
in mainWindow
go to page "opening"
end in
end
to handle showCaseList
send closeOtherViewers
in mainWindow
go to page "Case List"
end in
end
to handle showCopyright
open viewer "credits"
currentPage of viewer "credits" = page "copyright"
show viewer "credits"
end
to handle showCases
system curMediaType
syslockscreen = true
in mainwindow
if name of this page <> "Scene Presentation"
go to page "Scene Presentation"
end if
end in
if isOpen of viewer "search" is true
close viewer "search"
end if
if isOpen of viewer "results" is true
close viewer "results"
end if
in mainWindow
if curMediaType <> ""
if curMediaType = "video"
send getVideo to page "Scene Presentation"
else
send getImage to page "Scene Presentation"
end if
end if
end in
end
to handle setDefaultcase
system curCase,curScene
--just in case they pick search from the Case List
curCase = textline 1 of text of field "cases"
curScene = 1
end
to handle showSearch
system curMediaType
curMediaType = ""
in mainwindow
if name of this page = "Scene Presentation"
mmclose all
if visible of group "video player" is true
curMediaType = "video"
end if
if visible of stage "imgStage" is true
curMediaType = "image"
end if
end if
show viewer "search"
caption of mainwindow = "Search - Child Abuse Risk Assessment"
end in
end
to handle showHelp
if isOpen of viewer "Help" is true
currentPage of viewer "Help" = page "helpIndex"
else
show viewer "help"
end if
end
to handle CloseOtherViewers
syslockscreen = true
if isOpen of viewer "factors";close viewer "factors";end if
if isOpen of viewer "abstracts";close viewer "abstracts";end if
if isOpen of viewer "results";close viewer "results";end if
if isOpen of viewer "search";close viewer "search";end if
if isOpen of viewer "credits";close viewer "credits";end if
if isOpen of viewer "searchList";close viewer "searchList";end if
if isOpen of viewer "help";close viewer "help";end if
end
--------------------------------------------------
--
-- Book setup and various useful functions
--
--------------------------------------------------
to handle EnterBook
--------------------------------------------------
-- BookPath is often useful
system string BookPath
BookPath = name of self
while BookPath <> NULL and last char of BookPath <> "\"
clear last char of BookPath
end
send linkAllDLLs
clear text of field "cases" of page "Case List"
send reader
end
to handle linkAllDLLs
linkDLL "TBDLG.DLL"
STRING textlineToList(STRING)
end linkDLL
end
--------------------------------------------------
to handle LeaveBook
--------------------------------------------------
system dataOpen
clear dataOPen
end
--------------------------------------------------
to get TrimEnd txt
--------------------------------------------------
-- Remove spaces and empty lines from end of text
while last char of txt is in (CRLF & " ")
clear last char of txt
end
return txt
end
to handle clearText
size of background "searchList" = 11300,12000
step i from 1 to 15
whichCat = "cat" & i
whichList = "list" & i
clear text of field (whichCat) of page "searchList"
clear text of field (whichList) of page "searchList"
hide field (whichCat) of page "searchList"
hide field (whichList) of page "searchlist"
end step
end
to handle setupSearchList
syscursor = 4
syslockscreen = true
in mainwindow
go to page "searchList"
end in
--we have to make sure we start with only the 15 max. This is
--included primarily as a safety precaution during development
send removeXtraFields
--then, we want to clear text and hide all existing fields on the page
--the default maximum is 15 cat and 15 list fields
send clearText
db = db("db01") -- Database ActiveX Control
-- Make sure the always-reader viewer which
-- contains the GisburneDB control is visible
dbViewer = viewer "ActiveX controls"
if not isOpen of dbViewer
open dbViewer -- use 'open' to keep it invisible
end
get extAction("closerecordset") of db
syssuspend = true
SQL = "SELECT category FROM categories ORDER BY sequence"
get extAction("OpenRecordset", SQL,"","","readonly") of db
conditions
when extGetProp("EOF") of db -- Don't move past end
txt = "End of File"
when extGetProp("BOF") of db -- Don't move past beginning
txt = "Beginning of File"
else
get extMove("Last") of db
recCount = extGetProp("recordcount") of db
get extMove("First") of db
-- Retrieve the case contents here
clear txt
fldName = "category"
step i from 1 to recCount
get extGetField(fldName) of db
-- Use the first line just in case the field is multi-line
put textline 1 of it & CRLF after txt
if not extGetProp("EOF") of db
get extMove("Next") of db
end if
end step
end conditions
text of field "Categories" of background "searchList" = TrimEnd(txt)
CatCount of this page = recCount
if recCount > 15 -- we need to add fields and increase the length of the page
--how many additional = recCount - 15
xtraFields = recCount - 15
newRows = round(xtraFields/3) + 1
--there are 3 sets horizontally: A, B, C
--we keep the columns aligned for each type of field: these do not change
catAX = item 1 of position of field "cat1"
listAX = item 1 of position of field "list1"
catBX = item 1 of position of field "cat2"
listBX = item 1 of position of field "list2"
catCX = item 1 of position of field "cat3"
listCX = item 1 of position of field "list3"
--we also maintain the same spacing between the fields throughout
--we need to know how the y coordinate must be increased
--y space between the cat and list fields
catListYspace = item 2 of bounds of field "list1" - item 4 of bounds of field "cat1"
listCatYspace = item 2 of bounds of field "cat4" - item 4 of bounds of field "list1"
--we know that the Y coordinates are determined by the position of the last default row
--containing fields 13,14, and 15.
catYstart = item 4 of bounds of field "list13" + listCatYSpace
catfieldCount = 15 -- next cat field will be 16
listFieldCount = 15
step i from 1 to newRows
step k from 1 to 3
increment catFieldCount
--within a row, the Y coordinate doesn't change
conditions
when k = 1
catX = catAX
when k = 2
catX = catBX
when k = 3
catX = catCX
end conditions
send drawCatField catX,catYStart
name of selection = "cat" & catFieldCount
hide selection
end step
--now, we have to adjust the Y coordinate for the list field
whichCat = "cat" & catFieldCount
listYStart = item 4 of bounds of field (whichCat) + catListYSpace
step k from 1 to 3
increment listFieldCount
conditions
when k = 1
listX = listAX
when k = 2
listX = listBX
when k = 3
listX = listCX
end conditions
send drawListField listX, listYStart
name of selection = "list" & listFieldCount
hide selection
end step
--now, adjust the y coordinate for the next row
whichList = "list" & listFieldCount -- should be the last list field created
catYStart = item 4 of bounds of field (whichList)
--add appropriate spacing
catYStart = catYStart + listCatYspace
--for each xtra row, make the page background 2000 units greater
tempHeight = item 2 of size of this background
item 2 of size of this background = tempHeight + 2000
end step
end if
step i from 1 to recCount
--set up individual labels for each category
tempContents = textline i of text of field "categories" of background "searchList"
tempName = "cat" & i
text of field (tempName) = tempContents
show field (tempName)
tempName = "List" & i
catName = tempContents
send fillList catName,i
if textOverflow of field (tempName) > 0
borderStyle of field (tempName) = scrolling
end if
show field (tempName)
end step
if recCount < 7 -- we will drop the starting position lower on the page
position of group "searchfields" of page "searchList" = 250,800
else
position of group "searchfields" of page "searchlist" =250,100
end if
in mainWindow
go to page "opening"
end in
sysCursor = 1
end
to handle drawCatField x,y
newx = x + 3530
newY = y + 320
draw field from x,y to newx,newY
fillColor of selection = 120,77.625,33.3125
borderstyle of selection = shadowed
textalignment of selection = left
fontface of selection = arial
fontstyle of selection = regular
fontsize of selection = 8
indents of selection = 144,144,144
transparent of selection = false
activated of selection = true
end
to handle drawListField x,y
draw field from x,y to x+3350,y+1350
fontFace of selection = Arial
fontSize of selection = 8
fillcolor of selection = white
textAlignment of selection = left
transparent of selection = false
fieldType of selection = "multiselect"
activated of selection = true
borderstyle of selection = inset
indents of selection = 144,144,144
script of selection = the mouseScript of this book
end
to handle removeXtraFields
tempList = objects of page "searchList"
step i from 16 to itemCount(tempList)
testCat = "cat" & i
testList = "list" & i
if isObject (field (testCat) of page "searchList")
show field (testCat) of page "searchList"
clear field (testCat) of page "searchList"
end if
if isObject (field (testList) of page "searchList")
show field (testList) of page "searchList"
clear field (testList) of page "searchList"
end if
end step
end
to handle fillList catName, whichList
db = db("db01") -- Database ActiveX Control
syssuspend = false
get extAction("closerecordset") of db
syssuspend = true
SQL = "SELECT Factor FROM Factors WHERE category= " & quote & catName & quote & " order by factor"
get extAction("OpenRecordset", SQL,"","","readonly") of db
conditions
when extGetProp("EOF") of db -- Don't move past end
txt = "End of File"
when extGetProp("BOF") of db -- Don't move past beginning
txt = "Beginning of File"
else
get extMove("Last") of db
rCount = extGetProp("recordcount") of db
get extMove("First") of db
-- Retrieve the case contents here
clear txt
fldName = "factor"
step i from 1 to rCount
get extGetField(fldName) of db
-- Use the first line just in case the field is multi-line
put textline 1 of it & CRLF after txt
if not extGetProp("EOF") of db
get extMove("Next") of db
end if
end step
end conditions
tempField = "List" & whichList
if txt contains "End of File"
txt = ""
end if
text of field (tempField) of page "searchList" = TrimEnd(txt)
show field (tempField)
end
to handle searchAll -- logical AND
system factorList
clear factorlist
send getFactors
factorCount = textlineCount(factorList)
if factorCount = 0
break to system
end if
--to get this to build properly, had to observe how the parentheses work. Choices = factorCount
--rules: 1 choice; need 0 parenthesis after FROM; 1 parenthesis before WHERE
-- 2 choices; need 2 parentheses after FROM; 2 parentheses before WHERE
-- where x = 3 or more choices: need (x-1) parentheses after FROM; 1 before where
fromParen = ""
whereParen = ")"
conditions
when factorCount = 1
fromParen = ""
when factorCount = 2
fromParen = "(("
whereParen = "))"
when factorCount > 2
step i from 1 to factorCount - 1
fromParen = fromParen & "("
end step
end conditions
SQL2 = ""
step i from 1 to factorCount
SQL2 = SQL2 & " INNER JOIN FactorsByScenes AS FactorsByScenes_" & i & " ON ([FactorsByScenes].[CaseName] = FactorsByScenes_" & i & ".CaseName) AND ([FactorsByScenes].[SceneNumber] = FactorsByScenes_" & i & ".SceneNumber))"
end step
clear last char of SQL2 --gets rid of the extra ) at end
clear last char of SQL2
k = 1
r = 0
SQL3 = ""
SQL3 = SQL3 & whereParen & " WHERE ((([FactorsByScenes].[Factor])= " & textline k of factorList & ")"
if factorCount > 1
step i from 2 to factorCount
increment k
increment r
SQL3 = SQL3 & " AND ((FactorsByScenes_" & r & ".Factor) = " & textline k of factorList & ") "
end step
end if
-- Make sure the always-reader viewer which
-- contains the GisburneDB control is visible
dbViewer = viewer "ActiveX controls"
if not isOpen of dbViewer
open dbViewer -- use 'open' to keep it invisible
end
db = db("db01") -- Database ActiveX Control
syssuspend = false
get extAction("closerecordset") of db
syssuspend = true
SQL1 = "SELECT DISTINCT [FactorsByScenes].[CaseName], [FactorsByScenes].[SceneNumber], [FactorsByScenes].[Factor] FROM " & fromParen & "FactorsByScenes "
SQL = SQL1 & SQL2 & SQL3 & ")"
get extAction("OpenRecordset", SQL,"","","readonly") of db
conditions
when extGetProp("EOF") of db -- Don't move past end
txt = "End of File"
when extGetProp("BOF") of db -- Don't move past beginning
txt = "Beginning of File"
else
get extMove("Last") of db
rCount = extGetProp("recordcount") of db
get extMove("First") of db
-- Retrieve the case contents here
clear txt
fldName1 = "CaseName"
fldName2 = "SceneNumber"
step i from 1 to rCount
get extGetField(fldName1) of db
tempCaseName = it
get extGetField(fldName2) of db
tempSceneNumber = it
-- Use the first line just in case the field is multi-line
put tempCaseName & " " & tempSceneNumber & CRLF after txt
if not extGetProp("EOF") of db
get extMove("Next") of db
end if
end step
end conditions
if txt contains "End of File"
txt = ""
end if
text of field "caseSceneList" of page "caseSceneList" = TrimEnd(txt)
show viewer "Results"
end
to handle searchAny -- logical OR
system factorList
clear factorlist
send getFactors
factorCount = textlineCount(factorList)
if factorCount = 0
break to system
end if
orList = ""
orList = "factor = " & textline 1 of factorList
step i from 2 to factorCount
orList = orList & " or factor = " & textline i of factorList
end step
if orList = ""
break to system
end if
-- Make sure the always-reader viewer which
-- contains the GisburneDB control is visible
dbViewer = viewer "ActiveX controls"
if not isOpen of dbViewer
open dbViewer -- use 'open' to keep it invisible
end
db = db("db01") -- Database ActiveX Control
syssuspend = false
get extAction("closerecordset") of db
syssuspend = true
SQL = "SELECT distinct CaseName, SceneNumber FROM FactorsByScenes where " & orList
get extAction("OpenRecordset", SQL,"","","readonly") of db
conditions
when extGetProp("EOF") of db -- Don't move past end
txt = "End of File"
when extGetProp("BOF") of db -- Don't move past beginning
txt = "Beginning of File"
else
get extMove("Last") of db
rCount = extGetProp("recordcount") of db
get extMove("First") of db
-- Retrieve the case contents here
clear txt
fldName1 = "CaseName"
fldName2 = "SceneNumber"
step i from 1 to rCount
get extGetField(fldName1) of db
tempCaseName = it
get extGetField(fldName2) of db
tempSceneNumber = it
-- Use the first line just in case the field is multi-line
put tempCaseName & " " & tempSceneNumber & CRLF after txt
if not extGetProp("EOF") of db
get extMove("Next") of db
end if
end step
end conditions
if txt contains "End of File"
txt = ""
end if
text of field "caseSceneList" of page "caseSceneList" = TrimEnd(txt)
show viewer "Results"
end
to handle getFactors
system factorList
factorList = ""
k = 1
listCount = the catCount of page "searchList"
--now we know how many fields were created to hold individual factors
--for querying, we really don't care which category they're associated with
step i from 1 to listCount
whichField = "list" & i
tempList = the selectedTextlines of field (whichField) of page "searchlist"
if tempList <> null
tempCount = itemCount(tempList)
step p from 1 to tempCount
x = item p of tempList
textline k of factorList = quote & textline x of text of field (whichField) of page "searchlist" & quote
increment k
end step
end if
end step
end
to handle setupCase whichLine
system curCase,curScene,caseList,sceneList,sceneTotal,searchList
clear searchList
-- local int whichCase
curCase = item 1 of textline (whichLine) of text of field "cases" of page "Case List"
curScene = 1 --we always start with scene 1 from here
text of combobox "selectCase" of page "Scene Presentation" = curCase
--we need to create a list of scenes based on the total scene count for
--the current case. So, first we have to find that info
tempCaseList = textlineToList(caseList)
get ASYM_ItemOffset(curCase,tempCaseList)
whichCase = it
sceneTotal = textline whichCase of sceneList
step i from 1 to sceneTotal
textline i of tempList = i
end step
text of field "caseSceneInfo" of page "Scene Presentation" = "Case: " & curCase & crlf & "Scene: " & curScene
go to page "Scene Presentation"
syscursor = 1
end
=====END OF BOOK SCRIPT============
to handle firstIdle
system caseCount,caseList,sceneList,orderList
system STRING BookPath,dataOpen
system STRING dynamic caseArray[][]
caption of mainwindow = "Welcome to Child Abuse Risk Assessment (CARA)"
db = db("db01") -- Database ActiveX Control
-- Make sure the always-reader viewer which
-- contains the GisburneDB control is open, but invisible
dbViewer = viewer "ActiveX controls"
if not isOpen of dbViewer
open dbViewer -- use 'open' to keep it invisible
end
syssuspend = false
get extAction("closerecordset") of db
syssuspend = true
--we don't provide any flexibility about the location of the data file, but you could.
--the data file is expected to be in a folder called "data", off the location of the book
dbName = bookPath & "data\caradata.mdb"
if dataOpen <> "true"
show field "loading"
get extAction("opendatabase",dbName,"","readonly") of db
dataOpen = true
clear orderList
get extAction("openrecordset","Cases","","","readonly") of db
conditions
when extGetProp("EOF") of db -- Don't move past end
txt = "The Cases table appears to be empty. Please notify the program administrator."
request txt
break to system
else
get extMove("Last") of db
recCount = extGetProp("recordcount") of db
get extMove("First") of db
-- Retrieve the case contents here
step i from 1 to recCount
get extGetField("CaseName") of db
tmpCase = it
get extGetField("SceneCount") of db
tmpCount = it
caseArray[i][1] = tmpCase,tmpCount
if not extGetProp("EOF") of db
get extMove("Next") of db
end if
end step
end conditions
caseCount = item 1 of dimensions(caseArray)
clear caseList
clear sceneList
step i from 1 to caseCount
textline i of caseList = item 1 of caseArray[i][1]
textline i of sceneList = item 2 of caseArray[i][1]
end step
text of field "Cases" of page "Case List" = caseList
dropdownitems of combobox "selectcase" of page "Scene Presentation" = caseList
--sceneList holds the total number of scenes for each case
send setUpSearchList
end if
hide field "loading" of page "opening"
end
Script for page “Scene Presentation”
--------------------------------------------------
to handle firstIdle
--------------------------------------------------
system curCase,curScene
caption of mainwindow = "Cases and Scenes - Child Abuse Risk Assessment (CARA)"
syscursor = 4
syslockscreen = true
if curCase = null
send setUpCase 1
end if
if curCase <> null and curScene <> null
send ResetPage
end if
--we'll retrieve "all factors" only once per page, since this list doesn't change
send getAllFactors
syscursor = 1
end
--------------------------------------------------
to handle ResetPage
--------------------------------------------------
system curCase,curScene, searchList
syscursor = 4
mmclose all
syslockscreen = true
db = db("db01") -- Database ActiveX Control
-- Make sure the always-reader viewer which
-- contains the GisburneDB control is visible
dbViewer = viewer "ActiveX controls"
if not isOpen of dbViewer
open dbViewer -- use 'open' to keep it invisible
end
--we close only open recordsets, but leave the database open, since we use only one throughout
syssuspend = false
get extAction("closerecordset") of db