\begindata{text,538487060} \textdsversion{12} \template{default} \define{global

\begindata{text,538487060}
\textdsversion{12}
\template{default}
\define{global
}
\define{itemize
}
\formatnote{\chapter{Example 11:
\indexi{External representation}
Data streams}} \indexi{Data streams}
\indexi{Data objects++Data stream}
\indexi{Data objects++Reading}
\indexi{Data objects++Writing}
\indexi{Insets}
Example 11 illustrates how to store data and read it from a file. We
will
modify the previous example to store (i.e. write) the coordinates of the
hello
world string in a file. Then, when the file is read in, the string will
be
redrawn at the stored coordinate position.
The discussion that follows presents a step-by-step description of how to
modify the \italic{helloworld} class in Example 10 to produce Example 11,
which will read and write the coordinate position data of the
\italic{hello
world} string to permanent storage (a file). If you were to follow the
steps,
you would produce a program, called \italic{helloworldapp}, in seven
files:
\itemize{
a hello.ch file -- will contain the class definition for the
\italic{helloworld }data object, which overrides the \italic{Read} and
\italic{Write} methods of class \italic{dataobject}.
a hello.c file -- will contain statements that import Andrew Toolkit
classes
used by the data object, initialize the class, and define the
\italic{Read}
and \italic{Write} methods.
a hellov.ch file -- will contain the class definition for the
\italic{helloworld} view, and is exactly the same as in the previous
example.
a hellov.c file -- will contain statements that import Andrew Toolkit
classes
used by the view and definitions of the methods. This will be similar to
the
previous example, with the addition of function that handle the input and
output to and from the view.
a helloa.ch file -- will contain the class definition for the application
program that will display an instance of the class in a window. This
will be
exactly the same as in Example 10.
a helloa.c -- will contain declarations needed by the Andrew Toolkit
linking
and loading facilities as well the definition of the \italic{helloworld}
application method. This will be exactly the same as in Example 10.
Makefile -- will contain the directions for compiling, linking and
loading.
This will be exactly the same as Example 10.
}
For a complete listing of these files, see \italic{Program Listing for
Example
11} at the end of this section on p.
\begindata{textref,539236104}
\textdsversion{12}
# ExElevenListing\
\enddata{textref,539236104}
\view{textrefv,539236104,992,0,0}). The source code is available in the
directory /usr/andrew/examples/ex11.
Although the discussion of the steps refers directly to this example, the
information generally applies to the creation of any application that
reads
and writes data.
\begindata{bp,538929032}
\enddata{bp,538929032}
\view{bpv,538929032,993,0,0}
\section{Running the example program}
\formatnote{\bold{Action 1.} \formatnote{To run the program, at the
\bold{command }prompt type
runapp /usr/andrew/examples/ex11/helloa
and press the Enter key.
}
\bold{Response.}\formatnote{
\italic{hello world}
}The program will produce a window with
centered in the body of the window, vertical and horizontal scroll bars,
and a
message line strip.
\bold{Action 2.} \formatnote{
by
dragging it with
}Move \italic{hello world} in the window,
the right mouse button, or moving it with left mouse button hits.
\bold{Response. } \formatnote{
and the
message line
} \italic{hello world} will be redrawn
will display the message "Hello world at" followed by the coordinates
of the text string.
\bold{Action 3.}\formatnote{
\bold{Response. }\formatnote{
displayed
in the
}Choose \bold{Write} from the menu cards.
}The message "Write to file" will be
message line.
\bold{Action 4.}\formatnote{
Move
\italic{hello
}Type in a file name, and press Enter.
world} around again, and choose \bold{Read} from the menu cards.
\bold{Response.} \formatnote{
displayed in
the message
}The message "Read file" will be
line.
\bold{Action 5.}\formatnote{
\bold{Write} function
}Type in the file name you used for the
and hit Enter.
\bold{Response.} \formatnote{
the
position that
} \italic{hello world }will be redrawn in
was stored when you called the \bold{Write} function. If the screen was
black
when you chose Write, the screen will become black again, since that is
the
screen-color state that was stored.
\bold{Action 6.}\formatnote{
choose \bold{Quit}
}To quit the program, pop-up the menus and
from the top card.
\bold{Response.} \formatnote{
screen.
}The window will disappear from the
}
\begindata{bp,538929224}
\enddata{bp,538929224}
\view{bpv,538929224,994,0,0}
\section{Overview of the data stream}
All Andrew Toolkit applications must store data in files in a datastream
format. The datastream is a standard representation for data objects in
files.
\indexi{Data stream++Format}
It consists of a standard header, a object-specific part, and a standard
trailer. The header has the format:
\\begindata\{\italic{classname},\italic{objid}\}
where \italic{classname} is the name of the class, and \italic{objid} is
an
integer unique within the datastream. A newline following the header is
not
considered part of the data.
The format of the enddata part is similar:
\\enddata\{\italic{classname},\italic{objid}\}
If either of the strings "\\begindata" or "\\enddata" occur within the
object-specific part that is not actually the header for a sub-object,
the
backslash in front of the string should be escaped with another
backslash. In
general, escaping all backslashes with a backslash is safe.
\subsection{Defining the helloworld data object class} \indexi{Data
objects++Defining}
\formatnote{
#define POSUNDEF -1
class helloworld[hello]: dataobject[dataobj] \{
overrides:
Read(FILE *file,long id) returns long;
Write(FILE *file,long writeId,int level) returns long;
data:
long x,y;
boolean blackOnWhite;
\};
}
A major function of the data object class is the abstraction of permanent
storage. Subclasses of dataobject can override the \italic{Read} and
\italic{Write} methods with procedures to read and write its associated
data,
enabling any code that deals with dataobjects in general to also deal
with
this specific class.
\paragraph{Writing a data object to a file} \indexi{Data
objects++Writing}
The \italic{Write} method must write the contents of a dataobject to the
given
\italic{stdio} stream. The method takes four parameters. First, a
pointer to
the data object, and a file to be written to. Second, the
\italic{writeId}
parameter, which is a timestamp used to make sure we are not rewriting
the
same thing we just wrote. Therefore, we write only if the writeID is
different than the stored copy of the last writeID.
The \italic{level} parameter indicates whether or not this is the
"toplevel"
object being written (i.e., not a subobject within another object). An
object
is the toplevel object if the parameter is zero; thus, an object that is
writing out subobjects should call their Write methods with a non-zero
level
parameter. This distinction between toplevel and subobjects is important
especially if an object has both a datastream and a non-datastream
representation (e.g., text -- see Example 14). If an object is not the
toplevel object, it \italic{must} write itself out in datastream format,
as it
cannot make any assumptions about whether the objects writing it out can
handle either format.
Finally, the Write method should return its object's \italic{UniqueID},
which
is the uniqueId for the object/file itself can be used to distinguish
helloworld from other objects.
The following is the Write method for helloworld:
\formatnote{
long helloworld__Write(hw,file,writeId,level)
struct helloworld *hw;
FILE *file;
long writeId;
int level;
\{
if(writeId!=helloworld_GetWriteID(hw))\{ /* only write a given
version
once */
helloworld_SetWriteID(hw,writeId);
fprintf(file,"\\\\begindata\{%s,%d\}\\n",
class_GetTypeName(hw), helloworld_UniqueID(hw));
fprintf(file,"%d %d %d\\n",hw->x,hw->y,hw->blackOnWhite);
fprintf(file,"\\\\enddata\{%s,%d\}\\n",
class_GetTypeName(hw), helloworld_UniqueID(hw));
\}
return helloworld_UniqueID(hw);
\}
}
Helloworld's Write method only writes in the datastream format. The
method
first checks to make sure the Write is not a duplicate by looking at the
last
writeId, and then writes to \italic{file} the \italic{begindata} header,
the 3
numbers that represent the \italic{helloworld} state (i.e. the numbers
corresponding to x, y, and blackOnWhite), and the \italic{enddata}
trailer.
The class_GetTypeName calls gets the type for helloworld, and
helloworld_UniqueID gets the uniqueID for helloworld.
\paragraph{Reading a data object from a file} \indexi{Data
objects++Reading}
The \italic{Read} method takes a \italic{stdio} file pointer and an
\italic{id}. The \italic{id} is either zero, indicating that no data
stream
header was found, or an integer guaranteed to be unique within the data
stream. In the case that the \italic{id} is zero, some dataobjects may
try
and to read non-datastream formats, like a text object reading a normal
text
file or a raster object reading a graphics file; it probably should not
try to
read the \italic{enddata} either. Otherwise the stream is assumed to be
one
written by the object's Write routine, with the file pointer right after
the
\\begindata\{...\}. No version checking is done, although a particular
object
may implement its own.
The following is helloworld's Read method:
\formatnote{
long helloworld__Read(hw,file,id)
struct helloworld *hw;
FILE *file;
long id;
\{
char buf[100];
helloworld_SetID(hw,helloworld_UniqueID(hw));
if(fgets(buf,sizeof(buf),file)==NULL)
return dataobject_PREMATUREEOF;
/* the %hd tells sscanf that blackOnWhite is a short, not an int
*/
if(sscanf(buf,"%d %d %hd\\n",&hw->x,&hw->y,&hw->blackOnWhite)<3)
return dataobject_BADFORMAT;
if(fgets(buf,sizeof(buf),file)==NULL) /* read in the \\enddata\{...\}
*/
return dataobject_MISSINGENDDATAMARKER;
return dataobject_NOREADERROR;
\}
}
First, we set the ID for the read process by calling SetID with a pointer
to
the object and its uniqueID. The variable buf is used to store the text
strings as they are read.
The \italic{helloworld_Read} method tries to read two lines -- the
object-specific data, and the enddata trailer. If it cannot read all the
object-specific data, it returns a premature \smaller{EOF} error or a bad
format error; if it cannot read the \italic{enddata}, it returns a
missing-enddata error.
\subsection{The view I/O interface} \indexi{View++I/O interface}
\indexi{Data objects++View I/O interface}
The \italic{helloworldview} class has two procedures that are on the
\italic{helloworldview} menus -- Write and Read -- which call the
appropriate
procedure to write or read the \italic{helloworld} data object associated
with
the view. These procedures use the message string input facilities
discussed
in Example 9 to read in a filename from the user.
\indexi{Messages++Displaying}
\indexi{Messages++Questions}
\paragraph{Writing}
\formatnote{
static void writeHW(hwv,key)
struct helloworldview *hwv;
long key;
\{
char file[100], msgBuf[100];
FILE *fp;
message_AskForString(hwv,0,"Write file: ",NULL,file,sizeof(file));
fp=fopen(file,"w");
if(fp==NULL)\{
sprintf(msgBuf,"Couldn't open %s for writing.",file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
struct helloworld *hw=
(struct helloworld *)hwv->header.view.dataobject;
helloworld_Write(hw,fp,im_GetWriteID(),0);
fclose(fp);
\}
\}
}
This procedure simply prompts the user for the filename, opens a file,
calls
the \italic{helloworld_Write} procedure on its dataobject, and closes the
file.
\paragraph{Reading}
\formatnote{
static void readHW(hwv,key)
struct helloworldview *hwv;
long key;
\{
char file[100], msgBuf[100];
FILE *fp;
message_AskForString(hwv,0,"Read file: ",NULL,file,sizeof(file));
fp=fopen(file,"r");
if(fp==NULL)\{
sprintf(msgBuf,"Couldn't open %s for reading.", file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
char header[100];
if(fgets(header,sizeof(header),fp)==NULL)\{
sprintf(msgBuf,"Premature end-of-file in %s.",file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
char name[20];
int id;
if(sscanf(header,"\\\\begindata\{%[^,],%d\}\\n",
name,&id)!=2)\{
sprintf(msgBuf,"%s doesn't contain a
valid datastream header.", file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
struct helloworld *hw=
(struct helloworld *)hwv->header.view.dataobject;
if(strcmp(name,class_GetTypeName(hw))!=0)\{
sprintf(msgBuf, "%s doesn't contain a
helloworld dataobject.", file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
helloworld_Read(hw,fp,id);
fclose(fp);
helloworld_NotifyObservers(hw,0);
\}
\}
\}
\}
\}
}
The readHW procedure is slightly more complicated than the writeHW
procedure.
First, it checks to see if the file requested exists. Second, it parses
the
first line of the file it opens to make sure that it is both a valid
\italic{begindata} marker, and that the class is really a
\italic{helloworld}
dataobject. In all these cases, if the check comes back with an error,
an
appropriate error message is displayed in the program window to inform
the
user. If all the checks clear, the procedure finally calls the
\italic{helloworld_Read} method with the \italic{id} from the
\italic{begindata} header.
\begindata{bp,538928968}
\enddata{bp,538928968}
\view{bpv,538928968,995,0,0}
\paragraph{Binding the functions} \indexi{Bind}
\formatnote{
static struct bind_Description helloworldviewBindings[]=\{
\{"helloworld-center", "\\003",0, "Hello World,Center",0, Center,
"Center the helloworld string."\},
\{"helloworld-invert", "\\011",0, "Hello World,Invert",0, Invert,
"Invert the helloworld string."\},
\{"helloworld-relocate", "\\022",0, "Hello World,Relocate",0,
relocate, "Relocate the helloworld string."\},
\bold{\{"helloworld-read", NULL,0, "Hello World,Read",0, readHW,
"Read
in a new hello world."\},
\{"helloworld-write", NULL,0, "Hello World,Write",0, writeHW,
"Write out the current hello world to a file."\}},
NULL
\};
}
The bold face section is added to bind the \italic{readHW} and
\italic{writeHW}
functions for the program. Note that these are menu commands only;
there are
no key bindings for the functions.
The remainder of the program files and the Makefile and compilation
methods
are the same as in the previous example.
\begindata{bp,538929288}
\enddata{bp,538929288}
\view{bpv,538929288,996,0,0}
\begindata{texttag,539315976}
\textdsversion{12}
ExElevenListing\
\enddata{texttag,539315976}
\view{texttagv,539315976,997,0,0}
\section{Program listing for Example 11}
\formatnote{
\bold{hello.ch}
#define POSUNDEF (-1)
class helloworld[hello]: dataobject [dataobj]\{
overrides:
Read(FILE *file,long id) returns long;
Write(FILE *file,long writeId,int level) returns long;
data:
long x,y;
boolean blackOnWhite;
\};
\bold{\bold{\bold{\bold{hello.c}}}}
#include <stdio.h>
#include <class.h>
#include "hello.eh"
boolean helloworld__InitializeObject(classID,hw)
struct classheader *classID;
struct helloworld *hw;
\{
hw->x=POSUNDEF;
hw->y=POSUNDEF;
hw->blackOnWhite=TRUE;
return TRUE;
\}
long helloworld__Read(hw,file,id)
struct helloworld *hw;
FILE *file;
long id;
\{
char buf[100];
helloworld_SetID(hw,helloworld_UniqueID(hw));
if(fgets(buf,sizeof(buf),file)==NULL)
return dataobject_PREMATUREEOF;
/* the %hd tells scanf that blackOnWhite is a short, not an int */
if(sscanf(buf,"%d %d %hd\\n",&hw->x,&hw->y,&hw->blackOnWhite)<3)
return dataobject_BADFORMAT;
if(fgets(buf,sizeof(buf),file)==NULL) /* read in the \\enddata\{...\}
*/
return dataobject_MISSINGENDDATAMARKER;
return dataobject_NOREADERROR;
\}
long helloworld__Write(hw,file,writeId,level)
struct helloworld *hw;
FILE *file;
long writeId;
int level;
\{
if(writeId!=helloworld_GetWriteID(hw))\{ /* only write a given
version
once */
helloworld_SetWriteID(hw,writeId);
fprintf(file,"\\\\begindata\{%s,%d\}\\n",
class_GetTypeName(hw), helloworld_UniqueID(hw));
fprintf(file,"%d %d %d\\n",hw->x,hw->y,hw->blackOnWhite);
fprintf(file,"\\\\enddata\{%s,%d\}\\n",
class_GetTypeName(hw), helloworld_UniqueID(hw));
\}
return helloworld_UniqueID(hw);
\}
\bold{hellov.ch}
class helloworldview[hellov]: view \{
overrides:
FullUpdate(enum view_UpdateType type, long left, long top, long
width,
long height);
Update();
Hit (enum view_MouseAction action, long x, long y, long
numberOfClicks)
returns struct view *;
ReceiveInputFocus();
LoseInputFocus();
GetApplicationLayer() returns struct view *;
DeleteApplicationLayer(struct view *v);
GetInterface(int type) returns char *;
classprocedures:
InitializeClass() returns boolean;
data:
struct keystate *keystate;
struct menulist *menulist;
boolean haveInputFocus;
boolean HaveDownTransition;
long hitX,hitY;
long x,y;
boolean blackOnWhite;
long frameX, frameY;
long newFrameX, newFrameY;
int vrWidth,vrHeight;
\};
\bold{hellov.c}
#include <stdio.h>
#include <class.h>
#include "hellov.eh"
#include "graphic.ih"
#include "rect.h"
#include "keymap.ih"
#include "keystate.ih"
#include "menulist.ih"
#include "scroll.ih"
#include "bind.ih"
#include "message.ih"
#include "im.ih"
#include "hello.ih"
#define TOTALSIZE 1500
static void xgetinfo(), xsetframe(), ygetinfo(), ysetframe();
static long xwhat(), ywhat();
static struct scrollfns horizInterface = \{
xgetinfo, xsetframe, NULL, xwhat
\};
static struct scrollfns vertInterface = \{
ygetinfo, ysetframe, NULL, ywhat
\};
static struct keymap *helloworldviewKeymap;
static struct menulist *helloworldviewMenulist;
boolean helloworldview__InitializeObject(classID,hwv)
struct classheader *classID;
struct helloworldview *hwv;
\{
hwv->haveInputFocus = FALSE;
hwv->HaveDownTransition=FALSE;
hwv->keystate = keystate_Create(hwv, helloworldviewKeymap);
hwv->menulist = menulist_DuplicateML(helloworldviewMenulist, hwv);
hwv->newFrameX = hwv->newFrameY = 0;
return TRUE;
\}
struct view *helloworldview__GetApplicationLayer(hwv)
struct textview *hwv;
\{
return (struct view *)scroll_Create(hwv,scroll_LEFT+scroll_BOTTOM);
\}
void helloworldview__DeleteApplicationLayer(hwv,scrollbar)
struct textview *hwv;
struct scroll *scrollbar;
\{
scroll_Destroy(scrollbar);
\}
void helloworldview__FullUpdate(hwv, type, left, top, width, height)
struct helloworldview *hwv;
enum view_UpdateType type;
long left;
long top;
long width;
long height;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
struct rectangle myVisualRect;
helloworldview_GetVisualBounds(hwv,&myVisualRect);
hwv->vrWidth=rectangle_Width(&myVisualRect);
hwv->vrHeight=rectangle_Height(&myVisualRect);
if (hwv->newFrameX + hwv->vrWidth > TOTALSIZE)
hwv->newFrameX = TOTALSIZE - hwv->vrWidth;
if (hwv->newFrameY + hwv->vrHeight > TOTALSIZE)
hwv->newFrameY = TOTALSIZE - hwv->vrHeight;
hwv->frameX = hwv->newFrameX;
hwv->frameY = hwv->newFrameY;
if (hw->x == POSUNDEF) \{
hw->x = hwv->frameX + hwv->vrWidth / 2;
hw->y = hwv->frameY + hwv->vrHeight / 2;
\}
hwv->x=hw->x;
hwv->y=hw->y;
hwv->blackOnWhite=hw->blackOnWhite;
helloworldview_SetTransferMode(hwv, graphic_COPY);
if (hw->blackOnWhite)
helloworldview_FillRect(hwv, &myVisualRect,
helloworldview_WhitePattern(hwv));
else
helloworldview_FillRect(hwv, &myVisualRect,
helloworldview_BlackPattern(hwv));
helloworldview_SetTransferMode(hwv,graphic_INVERT);
helloworldview_MoveTo(hwv, hw->x - hwv->frameX, hw->y - hwv->frameY);
helloworldview_DrawString(hwv,"hello world",
graphic_BETWEENTOPANDBASELINE |
graphic_BETWEENLEFTANDRIGHT);
\}
void helloworldview__Update(hwv)
struct helloworldview *hwv;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
helloworldview_SetTransferMode(hwv, graphic_INVERT);
if (hw->blackOnWhite!=hwv->blackOnWhite) \{
struct rectangle vr;
helloworldview_GetVisualBounds(hwv,&vr);
helloworldview_FillRect(hwv,&vr,
helloworldview_BlackPattern(hwv));
hwv->blackOnWhite=hw->blackOnWhite;
\}
if (hwv->x!=hw->x || hwv->y!=hw->y || hwv->frameX!=hwv->newFrameX ||
hwv->frameY!=hwv->newFrameY) \{
if(hwv->x!=hw->x || hwv->y!=hw->y)\{
static char buf[100];
sprintf(buf,"Hello world at (%d,%d)",hw->x,hw->y);
message_DisplayString(hwv,0,buf);
\}
helloworldview_MoveTo(hwv,
hwv->x-hwv->frameX,
hwv->y-hwv->frameY);
helloworldview_DrawString(hwv, "hello world",
if(sscanf(header,"\\\\begindata\{%[^,],%d\}\\n",
name,&id)!=2)\{
graphic_BETWEENTOPANDBASELINE |
graphic_BETWEENLEFTANDRIGHT);
hwv->x=hw->x;
hwv->y=hw->y;
hwv->frameX = hwv->newFrameX;
hwv->frameY = hwv->newFrameY;
helloworldview_MoveTo(hwv,
hwv->x-hwv->frameX,hwv->y-hwv->frameY);
helloworldview_DrawString(hwv, "hello world",
graphic_BETWEENTOPANDBASELINE |
graphic_BETWEENLEFTANDRIGHT);
\}
\}
struct view *helloworldview__Hit(hwv, action, x, y, numberOfClicks)
struct helloworldview *hwv;
enum view_MouseAction action;
long x;
long y;
long numberOfClicks;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
if(hwv->HaveDownTransition)
switch(action)\{
case view_RightUp:
hwv->HaveDownTransition=FALSE;
/* fall through */
case view_RightMovement:
hw->x+=x-hwv->hitX;
hw->y+=y-hwv->hitY;
hwv->hitX=x;
hwv->hitY=y;
break;
case view_LeftUp:
hwv->HaveDownTransition=FALSE;
hw->x=x+hwv->frameX;
hw->y=y+hwv->frameY;
break;
case view_LeftMovement:
/* do nothing */
break;
default:
/* re-synchronize mouse */
hwv->HaveDownTransition=FALSE;
\}
if(!hwv->HaveDownTransition)
switch(action)\{
case view_RightDown:
hwv->hitX=x;
hwv->hitY=y;
/* fall through */
case view_LeftDown:
hwv->HaveDownTransition=TRUE;
helloworldview_WantInputFocus(hwv,hwv);
break;
\}
helloworld_NotifyObservers(hw,0);
return (struct view *)hwv;
\}
void helloworldview__ReceiveInputFocus(hwv)
struct helloworldview *hwv;
\{
hwv->haveInputFocus = TRUE;
hwv->keystate->next = NULL;
helloworldview_PostKeyState(hwv, hwv->keystate);
helloworldview_PostMenus(hwv, hwv->menulist);
\}
void helloworldview__LoseInputFocus(hwv)
struct helloworldview *hwv;
\{
hwv->haveInputFocus = FALSE;
\}
static void Center(hwv, rock)
struct helloworldview *hwv;
long rock;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
hw->x = hwv->newFrameX + hwv->vrWidth / 2;
hw->y = hwv->newFrameY + hwv->vrHeight / 2;
helloworld_NotifyObservers(hw,0);
\}
static void Invert(hwv, rock)
struct helloworldview *hwv;
long rock;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
hw->blackOnWhite = !hw->blackOnWhite;
helloworld_NotifyObservers(hw,0);
\}
static void relocate(hwv,rock)
struct helloworldview *hwv;
long rock;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
char buf[100];
int x,y;
message_AskForString(hwv,0,"New location (x,y):
",NULL,buf,sizeof(buf));
if(sscanf(buf,"%d,%d",&x,&y)!=2)
message_DisplayString(hwv,1,"Bad format; must be: number,number");
else\{
hw->x=x;
hw->y=y;
helloworld_NotifyObservers(hw,0);
\}
\}
static void readHW(hwv,rock)
struct helloworldview *hwv;
long rock;
\{
char file[100], msgBuf[100];
FILE *fp;
message_AskForString(hwv,0,"Read file: ",NULL,file,sizeof(file));
fp=fopen(file,"r");
if(fp==NULL)\{
sprintf(msgBuf,"Couldn't open %s for reading.", file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
char header[100];
if(fgets(header,sizeof(header),fp)==NULL)\{
sprintf(msgBuf,"Premature end-of-file in %s.",file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
char name[20];
int id;
if(sscanf(header,"\\\\begindata\{%[^,],%d\}\\n",
name,&id)!=2)\{
sprintf(msgBuf,
"%s doesn't contain a valid datastream header.",
file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
struct helloworld *hw=
(struct helloworld *)hwv->header.view.dataobject;
if(strcmp(name,class_GetTypeName(hw))!=0)\{
sprintf(msgBuf,
"%s doesn't contain a helloworld dataobject.",
file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
/* FINALLY, read the object in... */
helloworld_Read(hw,fp,id);
fclose(fp);
helloworld_NotifyObservers(hw,0);
\}
\}
\}
\}
\}
static void writeHW(hwv,rock)
struct helloworldview *hwv;
long rock;
\{
char file[100], msgBuf[100];
FILE *fp;
message_AskForString(hwv,0,"Write file: ",NULL,file,sizeof(file));
fp=fopen(file,"w");
if(fp==NULL)\{
sprintf(msgBuf,"Couldn't open %s for writing.",file);
message_DisplayString(hwv,1,msgBuf);
\}else\{
struct helloworld *hw=
(struct helloworld *)hwv->header.view.dataobject;
helloworld_Write(hw,fp,im_GetWriteID(),0);
fclose(fp);
\}
\}
static void xgetinfo(hwv, total, seen, dot)
struct helloworldview *hwv;
struct range *total, *seen, *dot;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
total->beg = 0;
total->end = TOTALSIZE;
seen->beg = hwv->frameX;
seen->end = hwv->frameX + hwv->vrWidth;
dot->beg = dot->end = hw->x;
\}
static void ygetinfo(hwv, total, seen, dot)
struct helloworldview *hwv;
struct range *total, *seen, *dot;
\{
struct helloworld *hw=(struct helloworld *)hwv>header.view.dataobject;
total->beg = 0;
total->end = TOTALSIZE;
seen->beg = hwv->frameY;
seen->end = hwv->frameY + hwv->vrHeight;
dot->beg = dot->end = hw->y;
\}
static void xsetframe(hwv, posn, cord, outof)
struct helloworldview *hwv;
int posn;
long cord, outof;
\{
hwv->newFrameX = posn - hwv->vrWidth * cord / outof;
if (hwv->newFrameX + hwv->vrWidth > TOTALSIZE)
hwv->newFrameX = TOTALSIZE - hwv->vrWidth;
else if (hwv->newFrameX < 0)
hwv->newFrameX = 0;
helloworldview_WantUpdate(hwv, hwv);
\}
static void ysetframe(hwv, posn, cord, outof)
struct helloworldview *hwv;
int posn;
long cord, outof;
\{
hwv->newFrameY = posn - hwv->vrHeight * cord / outof;
if (hwv->newFrameY + hwv->vrHeight > TOTALSIZE)
hwv->newFrameY = TOTALSIZE - hwv->vrHeight;
else if (hwv->newFrameY < 0)
hwv->newFrameY = 0;
helloworldview_WantUpdate(hwv, hwv);
\}
static long xwhat(hwv, cord, outof)
struct helloworldview *hwv;
long cord, outof;
\{
return hwv->frameX + hwv->vrWidth * cord / outof;
\}
static long ywhat(hwv, cord, outof)
struct helloworldview *hwv;
long cord, outof;
\{
return hwv->frameY + hwv->vrHeight * cord / outof;
\}
char *helloworldview__GetInterface(hwv, type)
struct helloworldview *hwv;
char *type;
\{
if (strcmp(type, "scroll,vertical") == 0)
return (char *) &vertInterface;
else if (strcmp(type, "scroll,horizontal") == 0)
return (char *) &horizInterface;
else
return NULL;
\}
static struct bind_Description helloworldviewBindings[]=\{
\{"helloworld-center", "\\003",0, "Hello World,Center",0,0, Center,
"Center the helloworld string."\},
\{"helloworld-invert", "\\011",0, "Hello World,Invert",0,0, Invert,
"Invert the helloworld string."\},
\{"helloworld-relocate", "\\022",0, "Hello World,Relocate",0,0,
relocate,
"Relocate the helloworld string."\},
\{"helloworld-read", NULL,0, "Hello World,Read",0,0, readHW, "Read in
a
new hello world."\},
\{"helloworld-write", NULL,0, "Hello World,Write",0,0, writeHW,
"Write out
the current hello world to a file."\},
NULL
\};
boolean helloworldview__InitializeClass(classID)
struct classheader *classID;
\{
helloworldviewMenulist=menulist_New();
helloworldviewKeymap=keymap_New();
bind_BindList(helloworldviewBindings,
helloworldviewKeymap,helloworldviewMenulist, &helloworldview_classinfo);
return TRUE;
\}
\bold{helloa.ch}
class helloworldapp[helloa] : application[app]\{
overrides:
Start() returns boolean;
\};
\bold{helloa.c}
#include <class.h>
#include "helloa.eh"
#include "im.ih"
#include "frame.ih"
#include "hello.ih"
#include "hellov.ih"
boolean helloworldapp__Start(hwapp)
struct helloworldapp *hwapp;
\{
struct helloworld *hw;
struct helloworldview *hwv;
struct view *applayer;
struct frame *frame;
struct im *im;
if(!super_Start(hwapp))
return FALSE;
hw=helloworld_New();
if(hw==NULL)
return FALSE;
hwv=helloworldview_New();
if(hwv==NULL) \{
helloworld_Destroy(hw);
return FALSE;
\}
applayer=helloworldview_GetApplicationLayer(hwv);
if(applayer==NULL) \{
helloworldview_Destroy(hwv);
return FALSE;
\}
frame=frame_New();
if(frame==NULL) \{
helloworldview_DeleteApplicationLayer(hwv,applayer);
return FALSE;
\}
im=im_Create(NULL);
if(im==NULL) \{
frame_Destroy(frame);
return FALSE;
\}
helloworldview_SetDataObject(hwv,hw);
frame_SetView(frame,applayer);
im_SetView(im,frame);
helloworldview_WantInputFocus(hwv,hwv);
return TRUE;
\}
\bold{Makefile}
SRCDIR=/usr/andrew/
INCLUDES= -I. -I$\{SRCDIR\}include/atk -I$\{SRCDIR\}include
INCLUDESRC = $\{SRCDIR\}include/atk
CC=cc
DEBUG = -g
TOOLS = $\{SRCDIR\}bin/
CFLAGS= $\{DEBUG\} $\{INCLUDES\}
CLASSFLAGS=$\{INCLUDES\}
MAKEDO = $\{TOOLS\}makedo $\{DEBUG\} -b $\{TOOLS\} -d $\{SRCDIR\}lib
CLASS = $\{TOOLS\}class
.SUFFIXES: .ih .eh .ch .do
.ch.ih:
$\{CLASS\} $\{CLASSFLAGS\} $*.ch
.ch.eh:
$\{CLASS\} $\{CLASSFLAGS\} $*.ch
.o.do:
$\{MAKEDO\} $<
all:
helloa.do hello.do hellov.do
helloa.do: helloa.o helloa.eh
hello.do:
hello.o hello.eh
hellov.do: hellov.o hellov.eh
helloa.o: helloa.c
helloa.o: $\{INCLUDESRC\}/app.ih
helloa.o: $\{INCLUDESRC\}/atom.ih
helloa.o: $\{INCLUDESRC\}/dataobj.ih
helloa.o: $\{INCLUDESRC\}/frame.ih
helloa.o: $\{INCLUDESRC\}/graphic.ih
helloa.o: $\{INCLUDESRC\}/im.ih
helloa.o: $\{INCLUDESRC\}/lpair.ih
helloa.o: $\{INCLUDESRC\}/message.ih
helloa.o: $\{INCLUDESRC\}/namespc.ih
helloa.o: $\{INCLUDESRC\}/observe.ih
helloa.o: $\{INCLUDESRC\}/point.h
helloa.o: $\{INCLUDESRC\}/rect.h
helloa.o: $\{INCLUDESRC\}/view.ih
helloa.o: $\{SRCDIR\}include/class.h
helloa.o: hello.ih
helloa.o: hellov.ih
helloa.o: helloa.eh
helloa.eh helloa.ih: helloa.ch
helloa.eh helloa.ih: $\{INCLUDESRC\}/app.ih
hello.o: hello.c
hello.o: $\{INCLUDESRC\}/atom.ih
hello.o: $\{INCLUDESRC\}/dataobj.ih
hello.o: $\{INCLUDESRC\}/namespc.ih
hello.o: $\{INCLUDESRC\}/observe.ih
hello.o: $\{SRCDIR\}include/class.h
hello.o: hello.eh
hello.eh hello.ih: hello.ch
hello.eh hello.ih: $\{INCLUDESRC\}/atom.ih
hello.eh hello.ih: $\{INCLUDESRC\}/dataobj.ih
hello.eh hello.ih: $\{INCLUDESRC\}/namespc.ih
hello.eh hello.ih: $\{INCLUDESRC\}/observe.ih
hellov.o: hellov.c
hellov.o: $\{INCLUDESRC\}/atom.ih
hellov.o: $\{INCLUDESRC\}/bind.ih
hellov.o: $\{INCLUDESRC\}/dataobj.ih
hellov.o: $\{INCLUDESRC\}/graphic.ih
hellov.o: $\{INCLUDESRC\}/keymap.ih
hellov.o: $\{INCLUDESRC\}/keystate.ih
hellov.o: $\{INCLUDESRC\}/menulist.ih
hellov.o: $\{INCLUDESRC\}/message.ih
hellov.o: $\{INCLUDESRC\}/namespc.ih
hellov.o: $\{INCLUDESRC\}/observe.ih
hellov.o: $\{INCLUDESRC\}/point.h
hellov.o: $\{INCLUDESRC\}/rect.h
hellov.o: $\{INCLUDESRC\}/scroll.ih
hellov.o: $\{INCLUDESRC\}/view.ih
hellov.o: $\{SRCDIR\}include/class.h
hellov.o: hello.ih
hellov.o: hellov.eh
hellov.eh hellov.ih: hellov.ch
hellov.eh hellov.ih: $\{INCLUDESRC\}/graphic.ih
hellov.eh hellov.ih: $\{INCLUDESRC\}/observe.ih
hellov.eh hellov.ih: $\{INCLUDESRC\}/point.h
hellov.eh hellov.ih: $\{INCLUDESRC\}/rect.h
hellov.eh hellov.ih: $\{INCLUDESRC\}/view.ih
hellov.eh hellov.ih: $\{SRCDIR\}include/class.h
}
\begindata{bp,537558784}
\enddata{bp,537558784}
\view{bpv,537558784,999,0,0}
Copyright 1992 Carnegie Mellon University and IBM.
All rights reserved.
\smaller{\smaller{$Disclaimer:
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
provided
# that the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of IBM not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission.
#
# THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ANY COPYRIGHT
# HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#
$
}}\enddata{text,538487060}