(BUS 13) Samples of Some Key Project Documents

by Kenneth L. Hess

This document contains extracts from the key project document for Banner Blue Software's program, Family Tree Maker for Windows (referred to throughout as FTW, FTM was the DOS version of the program). The first version of FTW was developed for Windows 3.1 during 1993.

Product Specific Objectives

These are the high-level objectives for the product the team is to build. This is how the team stated the objectives in 1993.

The following objectives are key to FTW's success:

  1. FTW is able to hold any digital information, period.

  2. FTW will provide the tightest integration of scanning (for both image input and output) of any product on the market, without exception.

  3. FTW will read FTM files without loss and it will provide generally the same output as FTM 2.0.

  4. FTW will have an extensible architecture, internally and externally, as a foundation for database merging, scripted presentations, and other advanced functionality. It will also meet Windows standards whenever reasonable.

  5. FTW will be reliable. [This is an embarassingly weak specification! -- Ken 5/20/98]

  6. As a project, FTW will be staffed so that a new version can be started immediately upon completion of the first version.

  7. See the Internal Product Specification for performance objectives which normally would be contained here.

Product Requirements Document

This document puts the project objectives into a working format. It contains:

The FTW Product Requirements Document had a total of thirty-two sections, two of which are extracted below. Every item listed was required in the final product unless it was labeled as "Desirable" or "Highly desirable." Since an MS-DOS version of this program was already on the market, the brief descriptions below sometimes imply a significant amount of functionality. The readers of the document knew that unless otherwise stated, everything about a feature in the MS-DOS version would have to be replicated in FTW.

15.0 Ancestor Tree

15.1 FTM format.

Highly desirable: Allow (optionally) a space saving layout where y-axis space is closed up for

missing individuals. (Like R-Plot.)

15.2 Single page option. With limits on what can print.

15.3 Multi-page option.

15.4 Print empty tree option.

15.5 Print empty branch option.

15.6 Option to print spouse (first, current) of primary individual.

15.7 Ahnentafel numbering option.

15.8 Desirable: Cascading trees.

15.9 Desirable: Option to print siblings of primary individual.

15.10 Desirable: Option to print siblings of all individuals.


26.0 Basic Editing of Fields and Positions

Undo Minimum of one level.




Paste Special...

Find Individual...

Field Labels...

Typing Saver... Ditto last identical field, ditto last field, macro capability




These are the blueprints. Software specifications are often broken into the two pieces below: an external and an internal spec.

External Product Specification

An External Product Specification is a detailed description of how the product appears to the end user. Consultations with customers, mock-ups, prototypes, and actual code should be used as appropriate to verify key parts of a design as early in the external specification process as possible.

Extracted below is a portion of the External Product Specification for FTW, dealing with the requirement for a "Find Individual" command called out in section 26.0 of the Product Requirements Document above.

Find Individual

The philosophy of the Find Individual command is to find too much rather than skip over what the user is looking for. Find Individual is accessible (currently) from the Family Page and the generic paginated views.

A key point is that this command is Find INDIVIDUAL. Many aspects of the behavior relate to finding a (single) person. For example, if several fields for one individual meet the criteria, the command navigates to the person once, not to the fields in succession.

The Answer Set

The program incrementally generates an answer set from the search criteria, allowing the user to navigate through the "found" items as they are located. Thus, if the user changes something in the answer set such that the search criteria is not met, it remains in the answer set until a new search is started. On the other hand, if someone modifies an individual not yet found so that they no longer meet the criteria, then they are never found.

If someone is deleted, they are dropped from the answer set. If a matching marriage or a matching object is deleted, the involved individual(s) remain in the answer set. In the specific case of a marriage, we would navigate back to the male, or the female if the male is deleted. (If this causes special problems, it's so obscure, it's not worth much work.)

If someone is added to the database during a search, they are found (if they meet the criteria) and their IND hasn't been searched yet. To the user, they may be found, they may not be found.

A new search is defined by any editing of the search criteria or by activation of the Restart button (which re-runs the search with the existing criteria). The criteria are remembered until explicitly cleared by the user. Thus, doing a search in the Index of Individuals destroys any other ongoing search.
Search Types and Criteria

Info presentation will be the same as in FTM (move to each Family Page or Album Page in order, or in the index, move the highlight). A table below indicates what to highlight when searching on a given item from a given location. The dialog box hovers on screen until the user cancels. It moves out of the way depending on what field is highlighted when found.

[The Change Item to Search dialog is list of fields and other items as shown below. Dialog design TBD.]

Field NameType Quantity per PersonSearch Type
Name48 char alpha1 Text
aka48 char alpha1 Text
Birth dateComment/event 1Date
Birth locationComment/event 1Text
Birth source informationSource 1Text
Death dateComment/event 1Date
Death locationComment/event 1Text
Death source informationSource 1Text
[In the actual specification, this table continued to describe 45 additional fields....]

Search TypeValid Search Criteria Finds
TextAny alphanumeric character(s) Any field containing the string (not case sensitive, not whole word)
!= All non-empty fields
= All empty fields
Text (special case for name)Additional restriction of 8 words max (if search is on "Any and all text fields", then only the first 8 words are applied to the name field)
DateM-D-YExact match & in range (abt, bef, aft, etc.)
M-YAny day in M-Y & in range
M-DAny year with M-D & in range
MAny day or year with M & in range
YAny day or month with Y & in range
?Entered as unknown
UNKNOWNEntered as unknown
EST <date>Exact match & in range
ABT <date>Exact match & in range
CIRCA <date>Exact match & in range
[In the actual specification, this table continued to describe approximately 25 additional conditions....]

NOTE: For version 1.0, case insensitivity for text searches will not apply to Unicode above 0xFF. Upper and lower case will represent different characters.

Name (text) fields have a restriction of between one and eight words in the search criteria. If you search only on punctuation in the name, you won't find anything.

If a shared object meets the criteria, every individual sharing the object is found.

An empty picture frame and an empty Note may be treated equivalently.

Parentless, childless individuals (individuals w/o children AND w/o parents) is a special search criterion. This is to assist in finding "lost" souls and litter from detach operations.

A "not within" search criteria is not required at this time.

This table shows what field or screen area is highlighted when an individual is found. Note that the view does not change when an individual is found.
Field Name Being SearchedSearching From Family Page Searching From Album Page (future)Searching From Index of Individuals
Default if field is erased or modified Name fieldTitle, Page 1 of n Name
NameName fieldTitle, Page 1 of n Name
akaName fieldTitle, Page 1 of n NA
Birth dateBirth date field Title, Page 1 of nNA
Birth locationBirth location field Title, Page 1 of nNA
Birth source informationName field Title, Page 1 of nNA
Death dateDeath date field Title, Page 1 of nNA
Death locationDeath location field Title, Page 1 of nNA
Death source informationName field Title, Page 1 of nNA
[In the actual specification, this table continued to describe 45 additional fields....]

If two or more fields/objects meet the criteria for a single individual, only the first (arbitrarily but consistently selected) is landed on.

1) If Find Individual on the Family Page finds a marriage or generic field where ther are two spouses, it will always put the cursor on the names of the spouses rather than on the field.

2) If Find Individual on the Marriage Notes or Marriage Facts finds an individual with no marriage or where the marriage has two spouses, it will switch to the Family Page. Rule 1 then governs where the cursor goes.

Once a field is landed on, any action by the user breaks out of the search. For example, if the user switches from the Family Page to the Ancestor Tree View during a search, the search dialog disappears.

If going backwards in an answer set to an individual whose field no longer matches, the default item is highlighted per the above table.

Desirable: Kinship will also be available as a search criterion (i.e. search for all first cousins of NAME).

Future: Multiple criteria search.

Future: Search on embedded or linked objects.

Internal Product Specification

The Internal Product Specification contains a detailed description of the overall product architecture and coding techniques to be applied for each feature. It is extremely important for this specification to detail the handling of all boundary and error conditions.

Extracted below is a portion of the Internal Product Specification for FTW, dealing with the requirement for a "Find Individual" command called out in section 26.0 of the Product Requirements Document and the External Product Specification above. It is far beyond the purposes of this note to describe what any of the material below actually means! Note also that the converter to put this on the Web totally botched the indentation and formatting of this section -- only software engineers will notice the difference.

Find Individual

Strictly speaking, Find Individual is part of the user interface, not the database. However, its workings are described here.

The Find Individual system supports four different dialogs: Find Individual, Add and Delete Individuals (for Individuals to Include), and Find Picture/Object. Although all four dialogs look and act differently, the code underneath is mostly shared.

The Find Individual and Find Picture/Object dialogs operate as free-floating modeless dialogs which communicate asynchronously via messages with the VIEW underneath them. They do not "understand" which VIEW is currently being displayed; in fact, for Find Individual, the VIEW can be changed dynamically.

Although only field-oriented VIEWs currently accept input from Find Individual, eventually it could be used to search through trees, kinship, etc..

It is the responsibility of each other VIEW/dialog in FTW to inform the Find Individual dialog as to whether the VIEW/dialog wants information from the Find Individual dialog or not.

Most of the actual messages are hidden procedurally.

A FINDIND is the static structure stored in the main data area of FTW within which the Find Individual dialog stores its static values. The structure is referred to via LPFINDIND and initialized via:

FindInt_InitStruct Performs the one-time initialization of a FINDIND structure.

Arguments: LPFINDIND lpfi

Return Type: -none-

Each VIEW (or the VIEW manager) should make the following call:

FindInd_Status_Change Informs a Find Individual or Find Picture Object dialog as to its new parent window, database, and how it is to act. Also, the basic kind of the dialog should be passed in.

Arguments: LPFINDIND lpfi

HWND hwndParent

DB dbDataBase



Return Type: -none-

The possible FINDINDOPTS are:

typedef enum {

FINDIND_START, /* bring up the Find Individual dialog */

FINDIND_ENABLE, /* ok to bring up Individual dialog */

FINDIND_RESET, /* get rid of the dialog, reset it, but don't

touch bOkToShow */

FINDIND_HIDE, /* get rid of the Find Individual dialog

temporarily */

FINDIND_DESTROY /* get rid of the dialog and reset it for a new

database */


Typically, FINDIND_START is used when the dialog is explicitly requested from the menu. When a VIEW is entered that doesn't mind if the dialog remains visible and active, it should set FINDIND_ENABLE; if it doesn't want the dialog to be visible, it should instead use FINDIND_HIDE. When a VIEW must cancel the dialog (perhaps because the temporary bits are going to be used for another purpose), it should use FINDIND_HIDE. Closing a DB should cause a FINDIND_DESTROY.

Possible FINDDIALOGS are:

typedef enum {

FINDDIALOG_FIND_INDIVIDUAL, /* Find Individual dialog */


dialog */

FINDDIALOG_ADD_INDIVIDUALS /* under Individuals to

Include */


Include */


The dialog may need to know the IND/MRG it is to work with. This is supplied via another function call:

FindInd_IndMrgInfo Informs a Find Individual dialog as to whom it is to search the ATTCHs for (in the case of FINDDIALOG_FIND_PICTURE_OBJECT) or whom the primary individual is (in the case of ancestor/descendant tree searches).

Arguments: LPFINDIND lpfi

IND ind

MRG mrg

Return Type: -none-

Once the above settings are established, the enabling of the "Find Individual/Scrapbook" menu item comes from:

FindInd_Menu_Active Returns TRUE iff the menu item "Find Individual" should be active.

Arguments: LPFINDIND lpfi

Return Type: BOOL

To keep a Find Ind dialog out of the way of fields being navigated through, VIEWs that use FINDIND_ENABLE should call:

FindInd_MoveAside Keeps the Find Individual dialog as far away from the hwndAvoid window as possible, but still within the hwndConstrain window. If the Find Individual dialog is hidden or has been terminated, there is no effect.

Arguments: LPFINDIND lpfi

HWND hwndAvoid

HWND hwndConstrain

Return Type: -none-

When the user presses Find Previous, Find Next, or Restart Search, the Find Individual dialog generally locates an IND/MRG/ATTCH to go to. When it does, it sends a VWM_SWITCH_IND, VWM_SWITCH_MRG_HUSBAND, VWM_SWITCH_MRG_WIFE, or VWM_SWITCH_ATTCH message to the currently active VIEW. Typical message handlers for these messages are:

XX_OnFindInd_Ind Handles the VWM_SWITCH_IND message sent to the VIEW. The VIEW should display the designated IND. The FIELDCODE does not always reflect the field found - however, per the EPS, the VIEW can decide which fields it is willing to move the focus to.

Arguments: HWND hwnd


IND ind

Return Type: -none-

XX_OnFindInd_Mrg Handles the VWM_SWITCH_MRG_HUSBAND and VWM_SWITCH_MRG_WIFE messages sent to the VIEW. The VIEW should display the designated IND who is the husband (if bHusband is TRUE) or wife (if bHusband is FALSE) of the MRG. The FIELDCODE does not always reflect the field found - however, per the EPS, the VIEW can decide which fields it is willing to move the focus to.

Arguments: HWND hwnd


MRG mrg

BOOL bHusband

Return Type: -none-

XX_OnFindInd_Attch Handles the VWM_SWITCH_ATTCH message sent to the VIEW. The VIEW should display the ATTCH with the designated index. The FIELDCODE does not always reflect the field found - however, per the EPS, the VIEW can decide which fields it is willing to move the focus to.

Arguments: HWND hwnd


DWORD ulIndex

Return Type: -none-

Standard message crackers are available:

#define HANDLE_VWM_SWITCH_IND(hwnd, wParam, lParam, fn) ...

#define HANDLE_VWM_SWITCH_MRG_HUSBAND(hwnd, wParam, lParam, fn) ...

#define HANDLE_VWM_SWITCH_MRG_WIFE(hwnd, wParam, lParam, fn) ...

#define HANDLE_VWM_SWITCH_ATTCH(hwnd, wParam, lParam, fn) ...

The Find Picture/Object dialog must ask the VIEW beneath it which ATTCH it is on. It uses the message:

VWM_WHICH_ATTCH Obtains the index of the current ATTCH from the Scrapbook View.

Arguments: HWND hwnd

Return Type: DWORD

As per the EPS, not all VIEWs can support all ..SWITCH.. possibilities at all times. For example, a Marriage Facts page should not show INDs who are married where the spouse will also be found because of the ambiguity over which person has been found. To switch to the family page under these circumstances, the VIEW should call:

FindInd_SwitchViews Tells the Find Individual dialog to switch VIEWs (presumably back to the family page) as the current VIEW receiving a VWM_SWITCH_... message cannot display the desired person.

Arguments: LPFINDIND lpfndindFindInd

Return Type: -none-

Because the Find Individual dialog creates a set of people who meet certain criteria, it must be told about deletions:

FindInd_DeletedInd Tells the Find Individual dialog that indToBeDeleted is about to be deleted. It is essential that this be called prior to the delete so that it can determine if the person was in the Find Individual set or not.

Arguments: LPFINDIND lpfndindFindInd

DB dbDataBase

IND indToBeDeleted

Return Type: -none-

[This section of the Internal Product Specification goes on for an additional five pages, including a description of relevant data structures.]