Figure 20-1 Arranging Spreadsheet Objects

This is how the sample spreadsheet objects are arranged on the page. Each 
Spreadsheet object (except for the controllers) is displayed in its own view. 
Applications will also have to declare a special view to space the objects 
properly. For an example of how the objects are declared, see Code 
Display 20-2 on page u 1227.
Warning

You should not keep 
ungrouped DB items 
locked.
Figure 20-0

Display 20-0

SwatDisplay 20-0

Table 20-0
20Spreadsheet Objects

Revision:  l

The spreadsheet objects provide most of the functionality that any 
spreadsheet will need. They let the user enter information in cells without 
direct involvement by the application. They also manage all interaction with 
the Parse library. The application can then ignore these issues, or it can 
intervene to add functionality.

Before you read this chapter, you should be familiar with the database 
routines (see "Database Library," Chapter 19 of the Concepts Book). In 
particular, you should be familiar with the section on the cell library. You 
should also have read the first few sections of the Parse Library chapter 
("Parse Library," Chapter 20 of the Concepts Book); you need not read the 
"Advanced Usage" section. You should also be familiar with Ruler objects 
("Ruler Object Library," Chapter 19) and VisComp objects ("VisComp," 
Chapter 24).

	20.1	Spreadsheet Overview

The spreadsheet library provides a high-level interface with the Cell and 
Parse libraries. It also provides all the user interface for a spreadsheet. The 
objects are subclassed from common Vis objects and inherit much of their 
functionality from them; this means that applications can alter spreadsheet 
objects in a very intuitive way. Applications can also use the spreadsheet 
objects in "engine" mode. When the Spreadsheet is in engine mode, it does not 
provide any user interface, but it still provides a convenient interface to the 
Cell and Parse libraries.

There are three main spreadsheet objects; most spreadsheet applications will 
use all three. Applications which use the spreadsheet in engine mode will not 
need to use all of the objects. There are also several controllers which work 
with the spreadsheet objects. Most spreadsheet applications will end up 
including all of these.

	20.1.1	Quick Look at the Objects

Three different classes of objects are provided for use with the spreadsheet. 
Most spreadsheet applications will use all three of these. To see how the 
objects are arranged, see Figure 20-1 on page u 1226

SpreadsheetClass
This is the main spreadsheet object, a subclass of 
VisCompClass. The spreadsheet object manages a cell file; it 
automatically looks up values for cells and displays them, and 
copies new data into the cell file. This object does the bulk of a 
spreadsheet application's work. Every open spreadsheet will 
have its own Spreadsheet object; applications usually use the 
Document Control to duplicate this object automatically for 
every open file. All references in the text to the "Spreadsheet 
Object" are to this object.

SpreadSheetRuler
This is a subclass of VisRulerClass. It is usually placed just to 
the left of the Spreadsheet object. It usually contains the labels 
for the cell rows; however, it can be set to show measurements 
in any of the standard forms (inches, centimeters, points, etc.). 
Like all rulers, it is usually displayed in a RulerView and is 
usually the Vis child of a RulerContent. It is linked to the 
Spreadsheet object, and thus it can automatically show 
information about the active area of the spreadsheet. Most 
applications will have two rulers, one horizontal and one 
vertical (determined by settings of the VRA_HORIZONTAL flag) 
One ruler will receive messages from the Spreadsheet; the 
other ruler will be its slave. For more information about rulers, 
see "Ruler Object Library," Chapter 19.

SSEditBarControlClass
This is a subclass of GenControlClass. The controller 
displays the value or formula for the active cell. The user can 
use this controller to change the value in a cell. The controller 
is usually made a child of the Edit menu, if there is one. As with 
all controllers, the user can put this controller wherever he 
prefers; it is usually put at the top of the primary window, just 
below the menu bar.

Other Controllers
The Spreadsheet library provides other controllers which do 
such things as add notes to cells, change row and column width, 
and sort rows or columns. Applications which include these 
objects will not have to perform these tasks directly.

	20.1.2	Managing Cell Files

As explained in "Database Library," Chapter 19 of the Concepts Book, cell 
files are ways of accessing DB items in a VM file. Ordinarily, every DB item is 
accessed via two tokens: the VM handle of the item's DB group, and the DB 
handle of the item. When items are arranged in a cell file, the application can 
access the items by a row and column address. In order to do this, the 
application must do some bookkeeping; for example, the application has to 
keep track of a CellFunctionParameters structure. If you use the 
spreadsheet objects, you can avoid this bookkeeping.

When you create a new spreadsheet file, the Spreadsheet object will allocate 
a "spreadsheet map" block in the file. (This is different from the ordinary VM 
map block; a file can have both a map block and a "spreadsheet map" block.) 
The spreadsheet objects will record essential bookkeeping information (such 
as the CellFunctionParameters structure) in this block. While it is 
running, it will cache the information in its own instance data; however, 
whenever the file is saved or updated, it will write the cache back to this 
block. The application should treat this block as entirely opaque.

When the spreadsheet object attaches a new file, it must be passed the 
handle of the spreadsheet map block. It can then read all the information it 
needs about the file. The spreadsheet will automatically allocate cells when 
needed, and free them when appropriate. Note that since cells are ungrouped 
DB items, whenever a cell is allocated or resized, potentially any or all 
ungrouped items in that VM file could be moved. For this reason, if you use 
ungrouped items, you should not leave them locked; it's probably safest not 
to use ungrouped items at all, if you can avoid them. (See section 19.2.4 of 
"Database Library," Chapter 19 of the Concepts Book.)

Every cell in a spreadsheet can contain one of three possible values: a 
number, a text string, or a token string. The application may set a cell's value 
with a message, or the user may set the selected cell's value with the 
SSEditBarControl. If the user entered a number in any acceptable format, 
the spreadsheet will set the cell's value to equal that number. If the user 
entered a character sequence which begins with an equals sign, the 
spreadsheet will call the parser to parse all the characters after the equals 
sign. If the sequence is a well-formed expression, the token sequence will be 
stored in the cell; otherwise an error will be displayed. If the user enters a 
character sequence which is not a well-formed number and does not begin 
with an equal sign, the spreadsheet object will interpret it as a string, and 
copy the string verbatim to the cell.

In addition, every cell can have a note associated with it. The note may be 
any null-terminated string. The note does not affect how the cell is evaluated. 
Users will generally add and view the notes with the SSNoteControl object.

Whenever the Spreadsheet changes any data in the file, it marks the 
appropriate block as dirty. If you use the Document Control objects, they will 
automatically take appropriate actions (such as enabling the "Save" trigger).

	20.1.3	Parsing Expressions

The Spreadsheet object automatically calls the appropriate Parse Library 
routines to parse formula strings, as well as to evaluate and format token 
strings. It performs all necessary interaction with the Parse library; for 
example, when the Evaluator needs to know the current value of a cell, the 
Spreadsheet find's the cell's contents, performs any evaluations necessary, 
and returns the data to the Evaluator. 

When the user enters a formula into a cell (i.e. a character sequence which 
begins with an equals sign), the spreadsheet automatically calls the Parse 
library routine to transform the character sequence into the corresponding 
token sequence. It stores the token sequence in the cell. It then calls the 
evaluator to simplify the token sequence. Finally, it calls the formatter to 
transform the simplified token sequence into a character string, and it 
displays this string in the spreadsheet display area. If the formula is 
well-formed, but cannot be evaluated (e.g. because it depends on a cell which 
has a bad value), it will display an appropriate error message in the cell. The 
formula is reevaluated whenever a the value of a cell or variable in the 
formula changes.

If the user wants to see or edit the actual formula, he can select the cell. The 
spreadsheet will call the formatter to transform the formula's token sequence 
back into a character string, which will be displayed in the edit bar, where 
the user can edit it. When the user is done editing, the new formula will again 
be parsed, and the new token sequence will be entered in the cell.

The Spreadsheet detects circular references; it can be instructed to break 
circular references, or to evaluate a set number of times through the circle to 
approximate the "true" value (i.e. the value if the circuit were followed an 
infinite number of times). Of course, this iteration is only useful if the cells' 
values converge.

	20.2	The Spreadsheet Objects

There are four basic objects in the Spreadsheet library. These objects are 
fairly simple to use. Most of the functionality is in the Spreadsheet object; the 
other objects are straightforward modifications of classes which are 
documented elsewhere.

	20.2.1	SpreadsheetClass


The spreadsheet object is the basis of the spreadsheet library. It does all the 
interaction with the cell and parse libraries. The spreadsheet has a lot of 
instance data fields. Some of them are of interest to the application; some are 
initialized by the application, and ignored thereafter; and some are of 
interest only to the spreadsheet object's internal code. The instance data is 
shown in Code Display 20-1. Those fields which are of interest to the 
application are described in detail in the following sections.

The spreadsheet object is a subclass of VisCompClass. If the spreadsheet is 
not being used in "engine" mode, it should be linked to a GenView object, just 
like any other VisComp object would be. For more information, "VisComp," 
Chapter 24.

Code Display 20-1 SpreadsheetClass Instance Data

/* This is the instance data for the SpreadsheetClass object. Some of these fields
 * must be initialized by the application; some are set and maintained entirely by
 * the object. */

/* The first field of the spreadsheet object is always the CellFunctionParameters
 * structure for the cell file. Therefore, a pointer to the instance data of a
 * Spreadsheet object can be used as a pointer to the CellFunctionParameters. */
    @instance CellFunctionParameters					SSI_cellParams= {0, 0, {0}};

/* SSI_maxRow and SSI_maxCol store the indices of the leftmost row and bottommost
 * column allowed in the spreadsheet. The application may set these; they must be
 * no larger than the spreadsheet library constants MAX_ROW (8191) and MAX_COLUMN
 * (255). */
    @instance word			SSI_maxRow = MAX_ROW;
    @instance word			SSI_maxColumn = MAX_COLUMN;

/* SSI_mapBlock is the VM handle of the attached file's spreadsheet map block. The
 * spreadsheet sets this when a spreadsheet file is initialized; applications must
 * provide this when they instruct a spreadsheet object to open a file. */
    @instance VMBlockHandle 			SSI_mapBlock;

/* SSI_flags is a word-length record of SpreadsheetFlags. Some of these flags are
 * set by the application; others are set automatically by the spreadsheet object.
 * The application can change some of these at run-time. The SpreadsheetFlags are
 * described at length in section 20.2.1.4 on page 1218. The following flags are
 * available:
 *		SF_MANUAL_RECALC				SF_ALLOW_ITERATION
 *		SF_SUPPRESS_REDRAW				SF_APPLICATION_FUNCTIONS
 *		SF_QUICK_DRAW_IN_PROGRESS				SF_DOING_FEEDBACK
 *		SF_IN_VIEW				SF_IS_TARGET
 *		SF_IS_FOCUS */
    @instance SpreadsheetFlags				SSI_flags = 0;

/* SSI_drawFlags is a word-sized record of SpreadsheetDrawFlags. These flags
 * specify how the spreadsheet will draw itself on-screen. The application can
 * change some of these at run-time. The SpreadsheetDrawFlags are described at
 * length in section 20.2.1.5 on page 1221. The following flags are available:
 *		SDF_DRAW_GRAPHICS			SDF_DRAW_NOTE_BUTTON
 *		SDF_DRAW_GRID			SDF_SIDEWAYS
 *		SDF_SCALE_TO_FIT			SDF_DRAW_ROW_COLUMN_TITLES
 *		SDF_SKIP_DRAW			SDF_CENTER_VERTICALLY
 *		SDF_CENTER_HORIZONTALLY			SDF_CONTINUOUS
 *		SDF_DRAW_HEADER			SDF_DRAW_FOOTER
 *		SDF_PRINT_DOCUMENT			SDF_PRINT_NOTES
 *		SDF_DONE
 */
    @instance SpreadsheetDrawFlags				SSI_drawFlags = 0;

/* SSI_attributes is a byte-sized record of SpreadsheetAttributes flags. The flags
 * are discussed at length in section 20.2.1.6 on page 1224. The following flags
 * are available:
 *		SA_TARGETABLE			SA_ENGINE_MODE */
    @instance SpreadsheetAttributes					SSI_attributes = 0;

/* SSI_circCount specifies how many times the Spreadsheet should follow circular
 * references to approximate the cells' values. This is ignored if the
 * SF_ALLOW_ITERATION bit is not set. If the count is set to zero, circular
 * references will be flagged as errors. */
    @instance word			SSI_circCount = 0;

/* SSI_converge specifies how close an approximation we want with circular
 * references. If each of the cells in a circular reference changes its value by
 * less than the SSI_converge value, the spreadsheet will stop following the loop.
 * If the converge value is left at zero, the spreadsheet will make the full
 * SSI_circCount circuits. */
    @instance FloatNum			SSI_converge = {0, 0, 0, 0, 0};

/* SSI_ruler must be set by the application when the objects are defined. This
 * field holds an optr to one of the two SpreadsheetRuler objects; the other ruler
 * should be a slave of this ruler. */
    @instance optr			SSI_ruler;

/* The following instance data fields are for internal use by the spreadsheet.
 * Applications should never set or change these fields, and should not count on 
 * values in these fields being consistent at any given time.*/

/* SSI_active contains a reference to the active cell. This field is automatically
 * set and maintained by the spreadsheet object. */
    @instance CellReference				SSI_active;

/* SSI_header and SSI_footer specify "header" and "footer" ranges of cells. These
 * cells will automatically be printed at the top and bottom of each page (when
 * the spreadsheet is printed). Users will generally set these with the Header and 
 * Footer controllers. */
    @instance CellRange			SSI_header = {0, 0, 0, 0};
    @instance CellRange			SSI_footer = {0, 0, 0, 0};

/* The spreadsheet object caches the CellFunctionParameters structure in its own
 * instance data, and writes it to the spreadsheet map block whenever the file is
 * saved or updated. The spreadsheet object initializes and updates this field
 * automatically. */
    @instance CellFunctionParameters 			SSI_cellParams = {0, 0, {0}};

/*
 * The following fields are intended to be entirely transparent to the
 * application. Applications should not examine, set, or change these fields.
 */

/* SSI_chunk is the chunk handle of the spreadsheet object. This is set and
 * maintained by the object. */
    @instance ChunkHandle 			SSI_chunk = NullHandle;

/* SSI_styleArray, SSI_nameArray, SSI_formatArray, and SSI_nameArray store the
 * handles of VM blocks within the spreadsheet file. These blocks contain
 * information about the file. The handles are also stored in the spreadsheet map
 * block. The spreadsheet object sets and maintains these fields automatically. */
    @instance VMBlockHandle 			SSI_styleArray;
    @instance VMBlockHandle 			SSI_rowArray;
    @instance VMBlockHandle 			SSI_formatArray;
    @instance VMBlockHandle 			SSI_nameArray;

/* SSI_offset is the offset to the visible portion of the spreadsheet. This field
 * is maintained automatically by the spreadsheet object. */
    @instance PointDWord 			SSI_offset;

/* SSI_offset stores the row and column indices of the currently visible portion
 * of the spreadsheet. This field is maintained automatically by the spreadsheet
 * object. */
    @instance CellRange 			SSI_visible;

/* SSI_quickSource is used for bookkeeping during a quick move/copy. During the
 * move, the row/column indices of the source area are stored here. */
    @instance CellRange 			SSI_quickSource;

/* SSI_selected contains the row/column indices of the currently selected region.
 * This field is automatically set and maintained by the spreadsheet object. */
    @instance CellRange 		SSI_selected;

/* SSI_curAttrs contains the token for the current style attributes. All text
 * entered will have this style. This field is automatically set and maintained by
 * the spreadsheet object. */
    @instance word 			SSI_curAttrs;

/* SSI_gstate is used to cache the gstate handle used for drawing to the screen.
 * This field is set and maintained by the spreadsheet object. */
    @instance word			SSI_gstate;

/* SSI_gsRefCount is used to keep track of the number of references to the gstate;
 * this lets the spreadsheet object know when to free the gstate. This field is
 * set and maintained by the spreadsheet object. */
    @instance byte			SSI_gsRefCount;

/* SSI_ancestorList, SSI_childList, and SSI_finalList are cached in the instance
 * data for efficiency. Applications should ignore these fields. */
    @instance word			SSI_ancestorList;
    @instance word			SSI_childList;
    @instance word			SSI_finalList;

/* SSI_bounds holds the bounds of the portion of the spreadsheet which contains
 * data. This field is set and maintained by the spreadsheet. */
    @instance RectDWord			SSI_bounds = {0, 0, 0, 0}



	20.2.1.1	SSI_mapBlock

The spreadsheet object has to keep track of certain information about files 
between executions. To do this, it writes data in a "spreadsheet map block." 
This block may be any VM block in the file containing the spreadsheet; it need 
not be the file's map block (indeed, it usually is not). When the spreadsheet 
object initializes a new spreadsheet file, it allocates a map block and returns 
the spreadsheet map block's VM handle. When you attach an existing file to 
the spreadsheet object (with MSG_SPREADSHEET_ATTACH_FILE), you must 
provide this handle; the spreadsheet will lock the map block and get all 
appropriate information from it. Applications may not access the 
spreadsheet map block directly; they should never lock or unlock it.

Initializing and attaching files is described at length in section 20.3.2 on page 
1230.

	20.2.1.2	SSI_maxRow and SSI_maxColumn

The application can specify the maximum dimensions for the spreadsheet. 
The upper-left corner of the spreadsheet is always cell A1 (row index 0, 
column index 0). The application can specify the maximum row and column 
indices allowed. These indices must be less than or equal to the constants 
MAX_ROW (8191) and MAX_COL (255).

	20.2.1.3	The Active Cell

One of the cells in a spreadsheet is always the "active" cell. When a formula 
or value is entered in the formula bar, the value is copied to the active cell. 
Similarly, the formula bar displays the formula for the active cell (whereas 
the cell's space in the spreadsheet displays the value to which the formula 
evaluates). The active cell's coordinates are stored in the fields SSI_curRow 
and SSI_curCol. Ordinarily, the user-not the application-sets the active 
cell, not the application. However, the application can change the active cell 
by sending the message MSG_SPREADSHEET_MOVE_ACTIVE_CELL.

n	MSG_SPREADSHEET_MOVE_ACTIVE_CELL



void	MSG_SPREADSHEET_MOVE_ACTIVE_CELL(

	word	row,	/* Move to cell with this row index */

	word	column);	/* and this column index */

This message instructs the spreadsheet to change the active cell. 
Applications should not usually need to send this message; they can rely on 
the spreadsheet's user interface for this.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	row	The row index of the new active cell. This should be 
specified in zero-based form; that is, the first row 
has an index of zero.

column	The column index of new active cell. This should be 
specified in zero-based form; that is, the first 
column has an index of zero.

Interception:	This message is not ordinarily subclassed.

	20.2.1.4	Recalculation and Iteration

SpreadsheetFlags, SpreadsheetRecalcParams, 
MSG_SPREADSHEET_CHANGE_RECALC_PARAMS, 
MSG_SPREADSHEET_GET_RECALC_PARAMS, MSG_SPREADSHEET_RECALC

The Spreadsheet object uses the SpreadsheetFlags record to keep track of 
details about the Spreadsheet's current state. Some of these fields are saved 
to the Spreadsheet map block, and some are not. There are only a two fields 
in this record that are of interest to the application:

SF_MANUAL_RECALC
If this flag is clear, whenever a cell's value is changed, the 
spreadsheet will automatically recalculate the cell's value (and 
the values of all cells which depend on it). If the flag is set, the 
application must force a recalculation by sending 
MSG_SPREADSHEET_RECALC to the spreadsheet object. By 
default, the flag is clear.

SF_ALLOW_ITERATION
If this flag is clear, the spreadsheet will not allow circular cell 
references (e.g. A1 = 10 + B1, B1 = 1/A1); all cells in a circular 
reference will evaluate to the error PSEE_CIRCULAR_REF, and 
all cells which depend on these cells will evaluate to 
PSEE_CIRCULAR_DEP. If the flag is set, the spreadsheet will 
follow circular references for a set number of circuits (specified 
in SSI_circCount) or until values converge within a specified 
tolerance (specified in SSI_converge).

Both of these flags are saved in the spreadsheet map block; thus, when a 
spreadsheet file is opened, these flags will be set to their values as of the last 
time the file was saved.

If you allow circular references, you must specify how many times a circuit 
will be followed. You do this by setting two instance data fields, 
SSI_circCount and SSI_converge. SSI_circCount specifies how many times a 
circuit should be followed in order to approximate the "true" values. If you set 
SSI_circCount to zero, the Spreadsheet will act the same as if 
SF_ALLOW_ITERATION had been cleared. You can also set a threshold value 
in the FloatNum datum SSI_converge. If, during a circuit, none of the cells' 
values change by more than the amount specified in SSI_converge, the 
spreadsheet will accept the values as accurate (even if it has not completed 
SSI_circCount circuits). If SSI_converge is set to zero, the spreadsheet will 
make the full SSI_circCount iterations.

To change the current recalculation parameters, send 
MSG_SPREADSHEET_CHANGE_RECALC_PARAMS to the spreadsheet object. 
This message takes one argument, a pointer to a 
SpreadsheetRecalcParams structure:

typedef struct {
	SpreadsheetFlags			SRP_flags;
	word			SRP_circCount;
	FloatNum			SRP_converge;
} SpreadsheetRecalcParams;

The spreadsheet object will set its SSI_circCount instance datum to equal the 
setting of SRP_circCount, and will set SSI_converge to equal SRP_converge. It 
will also set its SF_MANUAL_RECALC and SF_ALLOW_ITERATION flags to 
match their settings in SRP_flags; it will not change any of the other flags in 
SSI_flags.

To find out the current recalculation/iteration settings, call 
MSG_SPREADSHEET_GET_RECALC_PARAMS. This message takes one 
argument, namely a pointer to a SpreadsheetRecalcParams structure. 
The spreadsheet object will copy its SSI_flags, SSI_circCount, and 
SSI_converge data into the structure's SRP_flags, SRP_circCount, and 
SRP_flags fields.

n	MSG_SPREADSHEET_RECALC



void	MSG_SPREADSHEET_RECALC()

This message instructs the spreadsheet to recalculate the values of all of its 
cells. This message is needed if the spreadsheet has had automatic 
recalculation disabled; otherwise, the spreadsheet will automatically 
recalculate cells as needed.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	None.

Return:	Nothing.

Interception:	This message is not ordinarily subclassed.

n	MSG_SPREADSHEET_GET_RECALC_PARAMS



void	MSG_SPREADSHEET_GET_RECALC_PARAMS(

	SpreadsheetRecalcParams			*ssRecalcParams);

This message gets the current values of the Spreadsheet object's SSI_flags, 
SSI_circCount, and SSI_converge fields. The fields are copied into the 
corresponding fields of a SpreadsheetRecalcParams structure.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	ssRecalcParams	A pointer to a SpreadsheetRecalcParams 
structure. The data will be copied into this 
structure.

Return:	Appropriate values copied into *ssRecalcParams.

Structures:	SpreadsheetRecalcParams (described on page 1220).

Interception:	This message is not ordinarily subclassed.

n	MSG_SPREADSHEET_CHANGE_RECALC_PARAMS



void	MSG_SPREADSHEET_CHANGE_RECALC_PARAMS(

	const SpreadsheetRecalcParams*						ssRecalcParams);

This message changes the current values of the spreadsheet object's 
SSI_flags, SSI_circCount, and SSI_converge fields. The spreadsheet object 
copies the SpreadsheetRecalcParams structure's SRP_circCount, and 
SRP_converge fields into its own SSI_circCount and SSI_converge fields. It 
also sets its SF_MANUAL_RECALC and SF_ALLOW_ITERATION flags to 
correspond to the settings in SRP_flags; it does not change any of the other 
flags in SSI_flags.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	ssRecalcParams	A pointer to a SpreadsheetRecalcParams 
structure. The settings will be copied from this 
structure into the spreadsheet's instance data.

Return:	Nothing.

Structures:	SpreadsheetRecalcParams (described on page 1220).

Interception:	This message is not ordinarily subclassed.

	20.2.1.5	SpreadsheetDrawFlags

SpreadsheetDrawFlags, MSG_SPREADSHEET_GET_DRAW_FLAGS, 
MSG_SPREADSHEET_ALTER_DRAW_FLAGS

The application can specify how the spreadsheet should draw itself by setting 
the SpreadsheetDrawFlags. Many of these flags are relevant only when 
the spreadsheet is being printed; they are ignored when the spreadsheet is 
being drawn to the screen. The application can set these in the object 
declaration, or it can change them at run-time by sending 
MSG_SPREADSHEET_ALTER_DRAW_FLAGS. It can also find out the current 
settings by sending MSG_SPREADSHEET_GET_DRAW_FLAGS.

SpreadsheetDrawFlags has the following flags:

SDF_DRAW_GRAPHICS
Draw graphics associated with the spreadsheet.

SDF_DRAW_NOTE_BUTTON
Add glyphs in cells which contain notes, as well as in header or 
footer cells.

SDF_DRAW_GRID
Draw grid lines between cells.

SDF_SIDEWAYS
Draw the spreadsheet sideways. This is relevant only for 
printing.

SDF_SCALE_TO_FIT
Scale the selected range to fill a page. This is significant only 
for printing.

SDF_DRAW_ROW_COLUMN_TITLES 
Draw the row and column titles.

SDF_SKIP_DRAW
Do not draw anything to the screen. Set this if you want to find 
out how the pages will lie, without actually drawing or printing 
them.

SDF_CENTER_VERTICALLY
Center each page's contents vertically. This is relevant only for 
printing.

SDF_CENTER_HORIZONTALLY
Center each page's contents vertically. This is relevant only for 
printing.

SDF_CONTINUOUS 
Print the spreadsheet continuously; that is, don't leave space 
between pages or at the edges (or leave as little margin as the 
printer allows). This is relevant only for printing.

SDF_DRAW_HEADER
Print the header cells at the top of each page. This is relevant 
only for printing.

SDF_DRAW_FOOTER
Print the footer cells at the bottom of each page. This is 
relevant only for printing.

SDF_PRINT_DOCUMENT
This flag is never set or checked by the spreadsheet object. It is 
provided for the convenience of objects which use the 
spreadsheet.

SDF_PRINT_NOTES
This flag is never set or checked by the spreadsheet object. It is 
provided for the convenience of objects which use the 
spreadsheet.

n	MSG_SPREADSHEET_GET_DRAW_FLAGS



SpreadsheetDrawFlags 	MSG_SPREADSHEET_GET_DRAW_FLAGS()

This message returns the spreadsheet object's SSI_drawFlags instance data 
field.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	None.

Return:	Spreadsheet object's SSI_drawFlags field.

Interception:	This message is not ordinarily subclassed.

n	MSG_SPREADSHEET_ALTER_DRAW_FLAGS



void 	MSG_SPREADSHEET_ALTER_DRAW_FLAGS(

	SpreadsheetDrawFlags			bitsToSet,

	SpreadsheetDrawFlags			bitsToClear);

This message changes the settings of the spreadsheet object's SSI_drawFlags 
field. If the same bit is set in bitsToSet and bitsToClear, the results are 
undefined.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	bitsToSet	Turn on these flags in SSI_drawFlags.

bitsToClear	Turn off these flags in SSI_drawFlags.

Return:	Nothing.

Interception:	This message is not ordinarily subclassed.

	20.2.1.6	Engine Mode

SpreadsheetAttributes

Some applications will want to use the spreadsheet object to manage cell files 
and to interact with the parser, but will not want to use its user-interface. 
These applications can run the spreadsheet in "engine" mode. When the 
spreadsheet is in engine mode, it does not draw anything to the screen. 
Applications must arrange for the spreadsheet object to get data for cells, and 
must directly request data from the cells. 

To run a spreadsheet in engine mode, set the SA_ENGINE_MODE bit in the 
field SSI_attributes. This is the only field in SSI_attributes with which 
applications need concern themselves.

	20.2.1.7	SSI_ruler

The spreadsheet object needs to be linked to the SpreadsheetRuler objects. 
To set up the link, put an optr to one of the rulers in SSI_ruler; have the other 
ruler be a slave of the first.

	20.2.2	Spreadsheet Rulers


A special ruler object is defined for use with spreadsheets, 
SpreadsheetRulerClass. Applications can treat this the same way they 
treat ordinary ruler objects. Most applications will have two ruler objects, 
one horizontal and one vertical. Each of these should be a child of a 
RulerContent object, and should be displayed in a RulerView. For more 
information about rulers, see "Ruler Object Library," Chapter 19.

Each ruler has a single instance datum which ordinary rulers lack, namely 
SRI_spreadsheet. This field should be initialized to contain an optr to the 
spreadsheet object.

	20.2.3	The Spreadsheet Controller

Users enter data and formulae into the spreadsheet by using the 
Spreadsheet Edit-Bar Controller (i.e. SSEditBarControlClass, a subclass 
of GenControlClass). The controller is usually displayed in the tool-palette 
just below the menu bar; however, as with all controllers, the user can put 
the edit bar wherever he prefers.

The edit bar has two main functions: it is used to display the contents of cells, 
and it is used to change the contents. The spreadsheet object does not exactly 
display the contents of the cells. To be sure, if the cell contains a number or 
a string, the spreadsheet will display this in the cell's space; however, if the 
cell contains a formula, the spreadsheet will display not the formula, but 
rather the value to which the cell evaluates. For example, if a cell contains 
the formula "= 1 + 1", the spreadsheet object will display the number two in 
the cell. The edit bar, on the other hand, displays the contents of the active 
cell; in this case, it would display the text "= 1 + 1".

The edit bar is also used for changing the contents of cells. As noted, the edit 
bar displays the contents of the active cell. The user can change this text at 
will. The edit bar contains two special icons. One instructs the spreadsheet 
to store the new formula in the cell; this causes the edit bar to pass the string 
to the spreadsheet, which parses the string and stores the parsed version in 
the cell, then recalculates all affected cells. The other icon instructs the edit 
bar to throw out the changed version, and get the original formula from the 
spreadsheet. The edit bar also displays the coordinates of the active cell.


SSEditBarControlClass has no instance data (beyond what 
GenControlClass has). It uses only one message which is of interest to 
applications, namely MSG_SSEBC_INITIAL_KEYPRESS. This message is 
described below on page 1235.

	20.3	Basic Use

The spreadsheet objects are very simple to use. Once the application defines 
the objects, they almost run themselves. There are a few messages which 
applications have to know to send; these are described below. There are also 
some advanced utilities which applications may want to use.

	20.3.1	Declaring the Objects

The Spreadsheet objects are all subclassed off of fairly common objects, and 
should be declared the way those objects would be. The SSEditBarControl is 
generally the child of an "edit menu" interaction, and is often placed in the 
same resource as the edit menu; it should be run by the UI thread. The 
Spreadsheet and SpreadsheetRuler objects are usually put in the same 
resource. The rulers should be children of RulerContent objects. The 
spreadsheet object, as well as the ruler contents, should be displayed in their 
own GenView objects.

A simple usage of the spreadsheet objects is shown in Code Display 20-2 on 
page u 1227. The arrangement of objects can be confusing; Figure 20-1 on 
page u 1226 is a diagram of the various GenViews and GenInteractions and 
how they are arranged.

Code Display 20-2 Declaring the Spreadsheet Objects

/* First, we declare the Generic UI objects. These will be run by the UI thread.
 * Not all of the application's objects are shown here. */

@start Interface;

/* The SSEditBarControl is the child of an edit menu. It is declared just like any
 * other controller. */
@object SampleEditBarControl SSEditBarControl = {
    GI_visMoniker = "Edit bar";
    GI_visibility = dialog;
    HINT_EXPAND_WIDTH_TO_FIT_PARENT;
    HINT_GEN_CONTROL_USE_DEFAULT_TOOLS;
}

@end Interface

/*****************************************************************************
 * 	View Objects
 *****************************************************************************/

/* All of the views will be in a single resource. They will children of the
 * GenPrimary; GenInteraction objects are used to arrange the objects on the
 * screen. */

@start ViewResource;

/* This constant is used for sizing. */
#define RULER_WIDTH 			40
#define DOCUMENT_WIDTH 			MAX_COORD
#define DOCUMENT_HEIGHT			MAX_COORD



/* This GenInteraction contains all the Spreadsheet view objects. */
@object GenInteractionClass SampleOuterInteraction = {
    GI_comp = TopInteraction, BottomInteraction;
    HINT_ORIENT_CHILDREN_VERTICALLY;
    HINT_MINIMIZE_CHILD_SPACING;
    HINT_EXPAND_WIDTH_TO_FIT_PARENT;
    HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
}

/* This GenInteraction contains the horizontal ruler view, as well as a
 * space-filling corner view. */
@object GenInteractionClass TopInteraction = {
    GI_comp = CornerView, HorizRulerView;
    HINT_ORIENT_CHILDREN_HORIZONTALLY;
    HINT_MINIMIZE_CHILD_SPACING;
    HINT_EXPAND_WIDTH_TO_FIT_PARENT;
}

/* This GenInteraction contains the vertical ruler view and the Spreadsheet
 * object's view. */
@object GenInteractionClass BottomInteraction = {
    GI_comp = VertRulerView, SpreadsheetView;
    HINT_ORIENT_CHILDREN_HORIZONTALLY;
    HINT_MINIMIZE_CHILD_SPACING;
    HINT_EXPAND_WIDTH_TO_FIT_PARENT;
    HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
}

/* The CornerView is used to make the space where the horizontal and vertical
 * rulers meet. */
@object GenViewClass CornerView = {
    GI_attrs = @default & ~GA_TARGETABLE;
    GVI_attrs = @default | GVA_SAME_COLOR_AS_PARENT_WIN;
    GVI_horizAttrs = @default | GVDA_NO_LARGER_THAN_CONTENT;
    GVI_vertAttrs = @default | GVDA_NO_LARGER_THAN_CONTENT;
    ATTR_GEN_VIEW_PAGE_SIZE = {RULER_WIDTH, RULER_WIDTH};
    HINT_FIXED_SIZE = {HEADER_WIDTH, HEADER_WIDTH, 0};
}

/* These RulerViews are used to display the spreadsheet rulers. */

@object RulerViewClass HorizRulerView = {
    ATTR_GEN_VIEW_PAGE_SIZE = {DOCUMENT_WIDTH, RULER_WIDTH};
    HINT_FIXED_SIZE {0, HEADER_HEIGHT, 0};
    GVI_content = HorizRulerContent;
}

@object RulerViewClass VertRulerView = {
    ATTR_GEN_VIEW_PAGE_SIZE = {RULER_WIDTH, DOCUMENT_HEIGHT};
    HINT_FIXED_SIZE {0, HEADER_HEIGHT, 0};
    GVI_content = VertRulerContent;
}

/* The spreadsheet is displayed in its own view. The content of this view is the
 * spreadsheet object itself. As explained in section 20.3.3 on page 1234, this
 * view must have a special handler for MSG_META_KBD_CHAR; for this reason, we use
 * a subclass of GenViewClass. */
@object SampleSpreadsheetViewClass SpreadsheetView = {
    GVI_attrs = @default | GVA_CONTROLLED | GVA_DONT_SEND_POINTER_RELEASES 
		| GVA_DRAG_SCROLLING | GVA_WINDOW_COORDINATE_MOUSE_EVENTS;

    GVI_horizAttrs = @default | GVDA_SCROLLABLE;
    GVI_vertAttrs = @default | GVDA_SCROLLABLE;
    ATTR_GEN_VIEW_PAGE_SIZE = {DOCUMENT_WIDTH, DOCUMENT_HEIGHT};
    HINT_DEFAULT_FOCUS;
    HINT_DEFAULT_TARGET;
    GVI_CONTENT = SampleSpreadsheet;
}

@end ViewResource

/*****************************************************************************
 * 	Vis Objects
 *****************************************************************************/

/* These are the actual spreadsheet objects, as well as the contents in which the
 * rulers are displayed. The spreadsheet object is itself a subclass of
 * VisContent, so it need not be a child of a content. This resource is generally
 * run by the application thread. */

@start VisResource;

/* The spreadsheet object can generally be left with its default settings. */
@object SpreadsheetClass SampleSpreadsheet = {
    VI_bounds = {0,0,DOCUMENT_WIDTH, DOCUMENT_HEIGHT};
    VI_attrs = @default & ~VA_MANAGED;
    VI_optFlags = @default & ~VOF_GEOMETRY_INVALID & ~VOF_GEO_UPDATE_PATH;
    SSI_drawFlags = SDF_DRAW_GRID | SDF_DRAW_NOTE_BUTTON;
    SSI_ruler = HorizRuler;
}

/* Each ruler object is the child of a ruler content. */
@object RulerContentClass HorizRulerContent = {
    VI_bounds = {0,0, DOCUMENT_WIDTH, RULER_WIDTH};
    VI_attrs = @default & ~VA_MANAGED;
    VI_optFlags = @default & ~VOF_GEOMETRY_INVALID & ~VOF_GEO_UPDATE_PATH;
    VCI_comp = HorizRuler;
    VCNI_attrs = VCNA_SAME_HEIGHT_AS_VIEW | VCNA_LARGE_DOCUMENT_MODEL \
		| VCNA_WINDOW_COORDINATE_MOUSE_EVENTS;
}

/* We declare the HorizRuler as the "master" ruler; the spreadsheet sends messages
 * to it, and it relays them to the "slave" VertRuler. (It could as easily have
 * been the other way around.) */
@object SpreadsheetRulerClass HorizRuler = {
    VRI_type = VRT_CUSTOM;
    VI_bounds = {0, 0, DOCUMENT_WIDTH, RULER_WIDTH};
    VI_attrs = @default & ~ VA_MANAGED;
    VI_optFlags = @default & ~VOF_GEOMETRY_INVALID & ~VOF_GEO_UPDATE_PATH;
    SRI_spreadsheet = SampleSpreadsheet;
    VRI_slave = VertRuler;
    VRI_rulerAttrs = @default & ~(VRA_SHOW_GRID | VRA_SHOW_MOUSE | VRA_HORIZONTAL);
}

/* This is the content object for the vertical ruler. */
@object RulerContentClass VertRulerContent = {
    VI_bounds = {0,0, RULER_WIDTH, DOCUMENT_HEIGHT};
    VI_attrs = @default & ~VA_MANAGED;
    VI_optFlags = @default & ~VOF_GEOMETRY_INVALID & ~VOF_GEO_UPDATE_PATH;
    VCI_comp = HorizRuler;
    VCNI_rulerAttrs = VCNA_SAME_WIDTH_AS_VIEW | VCNA_LARGE_DOCUMENT_MODEL \
		 | VCNA_WINDOW_COORDINATE_MOUSE_EVENTS;
}

/* We declare the VertRuler as the "slave" ruler; it will get its messages from
 * the "master" HorizRuler. (It could as easily have been the other way around.) */
@object SpreadsheetRulerClass VertRuler = {
    VRI_type = VRT_CUSTOM;
    VI_bounds = {0, 0, RULER_WIDTH, DOCUMENT_HEIGHT};
    VI_attrs = @default & ~ VA_MANAGED;
    VI_optFlags = @default & ~VOF_GEOMETRY_INVALID & ~VOF_GEO_UPDATE_PATH;
    SRI_spreadsheet = SampleSpreadsheet;
    VRI_rulerAttrs = \
	(@default & ~(VRA_SHOW_GRID | VRA_SHOW_MOUSE)) | VRA_HORIZONTAL;
}

@end VisResource



	20.3.2	Working with Files

SpreadsheetInitFile(), SpreadsheetInitFileData, 
MSG_SPREADSHEET_ATTACH_FILE, MSG_SPREADSHEET_GET_FILE, 
MSG_SPREADSHEET_READ_CACHED_DATA, 
MSG_SPREADSHEET_WRITE_CACHED_DATA

The spreadsheet objects work with files almost transparently to the 
application. The application need only take a few steps to set things up and 
keep them working.

When an application creates a new spreadsheet file, it must first create a VM 
file, and then call SpreadsheetInitFile(). This routine initializes a cell file 
in the VM file; it also sets up the spreadsheet map block. It returns the handle 
of the spreadsheet map block; applications must store this, since they will 
need to pass it when they want to attach the file.

SpreadsheetInitFile() takes one argument: a pointer to a 
SpreadsheetInitFileData structure. SpreadsheetInitFileData has the 
following fields:

typedef struct {
	VMFileHandle			SIFD_file;
	word			SIFD_numRows;
	word			SIFD_numCols;
} SpreadsheetInitFileData;

SIFD_file	This is the VM handle of the spreadsheet file.

SIFD_numRows
	This is the number of rows in the spreadsheet. It is ordinarily 
equal to the spreadsheet's instance data field SSI_maxRow + 1.

SIFD_numCols
	This is the number of columns in the spreadsheet. It is 
ordinarily equal to the spreadsheet's instance data field 
SSI_maxCol + 1.

When an application has just initialized a new spreadsheet file or opened a 
pre-existing one, it must attach the file to the spreadsheet object. The 
application can do this by sending MSG_SPREADSHEET_ATTACH_FILE to the 
spreadsheet object. This message takes two arguments: the VM file's handle, 
and the VMBlockHandle of the spreadsheet map block. The spreadsheet will 
copy appropriate information from the spreadsheet map block into its own 
instance data and will display the visible cells. You can find out what file is 
attached by sending MSG_SPREADSHEET_GET_FILE to the spreadsheet 
object; this message returns the file's handle.

When you save the VM file, you must make sure that the spreadsheet copies 
all of its cached data to the file. That way the spreadsheet will be able to get 
up-to-date information when it restarts. To do this, send the message 
MSG_SPREADSHEET_WRITE_CACHED_DATA to the spreadsheet object. This 
message takes one argument, namely the handle of the VM file. This may be 
a new file if, for example, you are performing a "save-as" operation; the 
spreadsheet will assume that the file handle you pass supersedes its existing 
file handle. Applications which use the Document Control objects should 
send this message in their handlers for 
MSG_GEN_DOCUMENT_WRITE_CACHED_DATA_TO_FILE (see 
"GenDocument," Chapter 13).

At times, you may need to instruct the spreadsheet objects to reread its 
cached data from the file. For example, if you revert the file to its last-saved 
state, the spreadsheet will have to reread all its cached data. To do this, send 
MSG_SPREADSHEET_READ_CACHED_DATA to the spreadsheet object. This 
message takes two arguments: the file handle, and the spreadsheet map 
block's VMBlockHandle. These supercede the handles stored in the 
spreadsheet's instance data. The spreadsheet responds to this message by 
opening the specified map block and rereading its instance data from this 
block. Applications which use the Document Control objects should send this 
message in their handlers for 
MSG_GEN_DOCUMENT_READ_CACHED_DATA_FROM_FILE.

n	MSG_SPREADSHEET_ATTACH_FILE



void	MSG_SPREADSHEET_ATTACH_FILE(

	VMBlockHandle		mapBlockHandle,

	VMFileHandle		fileHandle);

This message instructs a spreadsheet object to attach itself to a spreadsheet 
file. The spreadsheet object will copy the appropriate information from the 
specified map block into its own instance data. Applications must send this 
when they open any spreadsheet file, whether a newly-initialized one or a 
pre-existing one.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	mapBlockHandle	The VMBlockHandle of the spreadsheet map block.

fileHandle	The VMFileHandle of the spreadsheet file.

Interception:	This message is not ordinarily subclassed.

n	MSG_SPREADSHEET_GET_FILE



VMFileHandle MSG_SPREADSHEET_GET_FILE()

This message returns the VMFileHandle of the file attached to the recipient 
Spreadsheet object.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	None.

Return:	The VMFileHandle of the attached file.

Interception:	This message is not ordinarily subclassed.

n	MSG_SPREADSHEET_READ_CACHED_DATA



void	MSG_SPREADSHEET_READ_CACHED_DATA(

	VMFileHandle		fileHandle,

	VMBlockHandle		mapBlockHandle);

This message instructs a spreadsheet object to read its cached data from the 
specified file and block. The handles passed supersede the handles in the 
Spreadsheet object's instance data. Applications which use the Document 
Control should send this message in their handlers for 
MSG_GEN_DOCUMENT_READ_CACHED_DATA_FROM_FILE.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	fileHandle	The VMFileHandle of the spreadsheet file.

mapBlockHandle	The VMBlockHandle of the spreadsheet map block.

Interception:	This message is not ordinarily subclassed.

n	MSG_SPREADSHEET_WRITE_CACHED_DATA



void	MSG_SPREADSHEET_WRITE_CACHED_DATA(

	VMFileHandle		file);

This message instructs the spreadsheet object to write any cached data to the 
spreadsheet file. The file handle passed supersedes any file handle in the 
spreadsheet's instance data. Applications which use the Document Control 
should send this message in their handlers for 
MSG_GEN_DOCUMENT_READ_CACHED_DATA_FROM_FILE.

Source:	Unrestricted.

Destination:	Any Spreadsheet object.

Parameters:	fileHandle	The VMFileHandle of the spreadsheet file.

Interception:	This message is not ordinarily subclassed.

	20.3.3	Interacting with the Edit Bar

The spreadsheet and the edit bar will work together with very little 
intervention from the application. There is only one task which the 
application needs see to personally.

When the user's focus is on the spreadsheet, some of the keypresses will be 
for navigation; for example, the arrow keys change the active cell. However, 
some keypresses will be intended for the formula bar. For example, if the 
focus is on the spreadsheet and the user types "=2+2", the user expects this 
to be entered in the formula bar; he will not want to have to click on the edit 
bar every time he wants to enter a formula. The application must determine 
if a keypress is intended for the spreadsheet or the edit bar.

For this reason, the application should define a subclass of GenViewClass 
and have the spreadsheet displayed in one of these objects. The subclass 
needs only one new thing: a handler for MSG_META_KBD_CHAR. When the 
view receives this message, it should decide whether to transfer the focus to 
the edit bar. If the character is a keyboard accelerator, a navigational key, or 
a key release, for example, the method should simply call its superclass 
method. However, if the keypress is intended for the edit bar (i.e. if it is an 
alphanumeric or punctuation character) the handler should send 
MSG_SSEBC_INITIAL_KEYPRESS to the edit bar. This message takes the 
same arguments as MSG_META_KBD_CHAR, so the MSG_META_KBD_CHAR 
handler can simply pass its own arguments along. When the edit bar receives 
this message, it will take the focus away from the spreadsheet's view, and will 
process that keypress and all succeeding keypresses until a navigational key 
is pressed. At that time, it will return the focus to the spreadsheet's view.

n	MSG_SSEBC_INITIAL_KEYPRESS



void	MSG_SSEBC_INITIAL_KEYPRESS(

	word	character,

	word	flags,

	word	state);

Spreadsheet objects are put in a subclass of GenViewClass. When this 
subclassed View receives a keypress (via MSG_META_KBD_CHAR), it must 
decide whether to process the keypress itself (by calling the superclass' 
handler for MSG_META_KBD_CHAR) or hand the keypress and the focus over 
to the spreadsheet edit bar. This message gives the keypress and the focus to 
the edit bar.

The arguments are the same as those to MSG_META_KBD_CHAR. Thus, the 
View can simply pass along the arguments it received with 
MSG_META_KBD_CHAR.

Source:	Subclass of GenViewClass whose content is Spreadsheet object; sent 
by handler for MSG_META_KBD_CHAR.

Destination:	SSEditBarControl object.

Parameters:	character	Key which was pressed. This is the character 
argument to MSG_META_KBD_CHAR.

flags	Character flags and shift state. This is the flags 
argument to MSG_META_KBD_CHAR.

state	ToggleState and scan code. This is the state 
argument to MSG_META_KBD_CHAR.

Return:	Nothing.

Interception:	This message is not ordinarily subclassed.

	20.4	Other Spreadsheet Controllers

The Spreadsheet Library provides several controllers which are designed to 
work with the Spreadsheet objects. These controllers act transparently to the 
application; you need merely declare them in your source code, and the user 
will be able to use them to modify the spreadsheet at will. All of these 
controllers should be on the application's GAGCNLT_SELF_LOAD_OPTIONS 
GCN list.

Other controllers are continually being added; as new ones are written, 
applications will be able to incorporate them easily into existing 
spreadsheets.

	20.4.1	The SSEditControl


This object implements the UI for clearing, inserting, and deleting cells.

	20.4.2	Notes and SSNoteControlClass


Every cell in a spreadsheet actually contains two pieces of information. One 
of these is the cell's number, string, or formula. It is this which is displayed 
in the spreadsheet window and in the formula bar; when we speak of a cell's 
value, we mean the cell's number or string, or the value to which the formula 
evaluates.

However, every cell can have another piece of information, namely a note. 
The note is a null-terminated text string. The note does not have any effect 
on the cell's value; it is used entirely for commenting.

If you declare an SSNoteControl object, the user will be able to see and 
change the notes. The SSNoteControl is much like the formula bar; it 
automatically displays the note for the active cell, and the user will be able 
to change it at will.

	20.4.3	Row and Column Size


Most spreadsheets will want to use the SSRowHeightControl and 
SSColumnWidthControl objects. These objects allow the user to change the 
height and width of the cells. As with the other controllers, these act 
transparently to the application.

	20.4.4	Sorting and SSSortControlClass


A controller has been provided which allows users to sort a group of rows or 
columns. The user can specify whether the sort is done in ascending or 
descending order. If you are sorting rows, the column containing the active 
cell is the index column; it contains the values by which the rows will be 
sorted. (For example, if the active cell is B4 and the user sorts "ascending by 
row," the row with the lowest value in column 4 will be first.)

The Sort controller automatically uses the localization libraries to sort 
strings in the local language's alphabetical order.

	20.4.5	Defining and Using Names


Users may often find it convenient to use names for cells or values. For 
example, a user may want to define "YearTotal" as a synonym for cell A1; 
whenever he uses YearTotal in an equation, the spreadsheet would use the 
value in cell A1. The Spreadsheet object supports this with the Name 
controller. The user can use the SSDefineNameControl controller to associate 
a name with a string, number, cell reference, or cell range. When the user 
enters a formula in a cell, the name will be passed through to the Parse 
routine. The evaluator will call the spreadsheet to find out what the current 
value of the name is and pass it back to the evaluator. All of this happens 
transparently to the application.


The user can also select one of the names he has defined, and paste it into the 
formula bar, by using the SSChooseNameControl object.

	20.4.6	Headers and Footers


The user can define a range of cells as a "header". When the spreadsheet is 
printed, the header will be displayed at the top of every page. Similarly, the 
user can specify a "footer" which will appear at the bottom of every printed 
page. The user uses the SSHeaderFooterControl to specify these ranges.
