home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
x
/
xhyper10.zip
/
XHyper_v1.0
/
src
/
TextView.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-08
|
18KB
|
765 lines
/*
* Copyright (c) 1992 U.S. Geological Survey (USGS)
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, 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 USGS not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. USGS makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* USGS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL USGS
* 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.
*
*/
/*
* TextView
*/
#include <InterViews/background.h>
#include <InterViews/box.h>
#include <InterViews/character.h>
#include <InterViews/color.h>
#include <InterViews/composition.h>
#include <InterViews/deck.h>
#include <InterViews/discretion.h>
#include <InterViews/font.h>
#include <InterViews/glue.h>
#include <InterViews/hit.h>
#include <InterViews/listener.h>
#include <InterViews/patch.h>
#include <InterViews/printer.h>
#include <InterViews/session.h>
#include <InterViews/strut.h>
#include <InterViews/style.h>
#include <InterViews/simplecomp.h>
#include <InterViews/texcomp.h>
#include <InterViews/world.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h>
#include "HyperView.h"
#include "list.h"
#include "PSFigItem.h"
#include "TextView.h"
#include "Tag.h"
/*-------------------------------------------------------------------------
Class TextView
This class is the heart of the On-Line Help display. It translates
the MML files, displays text and figures, and processes hypertext
requests.
Members:
appendchar - adds character to view
Count - returns number of pages in view
draw - draw the page
event - catch hypertext request
fontstyle - changes style of current font (e.g. bold)
jump_to - jump to hypertext offset
last_page - jump to last page
make_defaults - create default font and paragraph
MMLFile - returns name of file
parse_command - process an MML variable
printout - generate Postscript output
read - translate MML file
view_page - view specific page
wordhit - processes a hypertext request
*-------------------------------------------------------------------------*/
const Coord TEXTWIDTH = 450.0;
const Coord TEXTHEIGHT = 240.0;
//
// *** create Text information list structure (see list.h)
//
declareList(TextInfo_List,TextInfo)
implementList(TextInfo_List,TextInfo)
extern int getline(FILE*, char*);
TextView::TextView (HyperViewer* p, char* filename, int tindex)
: MonoGlyph(nil), Handler()
{
char fullname[256];
FILE *fd;
_home = (char*)getenv("HYPERDOC");
_parent = p;
_numfont = 0;
_numpar = 0;
_listener = new Listener(nil, this);
_text = new TextInfo_List(1000);
_ishyper = false;
_tocindex = tindex;
make_defaults();
_pages = new Deck();
//
// *** pages are broken into lines
//
_lines = new TBComposition(
_pages,
new SimpleCompositor(),
new Discretionary(
0,
new VStrut(0, TEXTHEIGHT, 20.0, 0, 0),
new VStrut(0, TEXTHEIGHT, 0.0, 0, 0), nil, nil
),
TEXTHEIGHT, 10
);
_lines->ref();
//
// *** lines are broken into characters
//
_characters = new LRComposition(
_lines,
new TeXCompositor(10),
nil,
TEXTWIDTH,
1000
);
_characters->ref();
//
// *** open and translate file
//
if (_home != NULL)
{
strcpy(fullname, _home);
strcat(fullname, "/");
strcat(fullname, filename);
}
else
strcpy(fullname, filename);
if ((fd = fopen(fullname, "r")) == (FILE*)NULL)
{
printf("Cannot open file: %s\n", filename);
exit(-1);
}
read(fd);
fclose(fd);
appendchar('\n');
_file = filename;
_characters->repair();
_lines->repair();
_patch = new Patch(_characters);
_listener->body(_patch);
_listener->button(true, Event::left);
_listener->key(true);
body(_listener);
_curpage = 1;
view_page(1);
}
TextView::~TextView()
{
_lines->unref();
_characters->unref();
delete _file;
delete _text;
delete _pages;
delete _patch;
delete _listener;
}
int TextView::Count()
{
return (_pages->count()/2);
}
const char* TextView::MMLFile()
{
return _file;
}
void TextView::view_page(int page)
{
page = 2*(page-1);
_pages->flip_to(page);
//
// *** find first and last characters of page
//
long first_line = _lines->beginning_of(page);
long last_line = _lines->end_of(page);
long first_char = _characters->beginning_of(first_line);
long last_char = _characters->end_of(last_line);
_characters->view(first_char, last_char);
_patch->reallocate();
_patch->redraw();
}
void TextView::event (Event& e)
{
char keystring[10];
Hit hit(e.pointer_x(), e.pointer_y());
//
// *** at present, only up events are processed
//
switch (e.type())
{
case Event::down:
break;
case Event::up:
_patch->repick(0, hit);
if (hit.any())
wordhit(hit.index(0));
break;
case Event::key:
break;
}
}
void TextView::wordhit(GlyphIndex i)
{
//
// *** tell parent of hypertext request
//
if (_text->item(i)._tocindex != 255)
_parent->hypertext(_text->item(i)._tocindex);
}
int TextView::last_page()
{
view_page((int)_pages->count()/2);
return(_pages->count()/2);
}
void TextView::jump_to(int offset)
{
int p;
long first_line;
long first_char;
long last_line;
long last_char;
//
// *** find page containing offset and inform parent
//
for (p = 0; p < _pages->count(); p++)
{
first_line = _lines->beginning_of(p);
last_line = _lines->end_of(p);
first_char = _characters->beginning_of(first_line);
last_char = _characters->end_of(last_line);
if (((first_char-2) <= offset) && (last_char > offset))
{
_parent->page_to(p/2+1);
break;
}
}
if (p == _pages->count())
_parent->page_to((int)(_pages->count())/2);
}
void TextView::read(FILE* fd)
{
char line[100];
int textout;
int eol;
int i;
boolean newline;
eol = false;
textout = false;
_fg = Session::instance()->style()->foreground();
_bg = Session::instance()->style()->background();
while (getline(fd, line) != EOF)
{
i = 0;
switch (line[0])
{
case ' ':
break;
case '\n':
if (textout)
{
appendchar('\n');
textout = false;
}
break;
//
// *** MML definition
//
case '<':
newline = parse_command(line, fd);
if (newline && textout)
{
appendchar('\n');
textout = false;
break;
}
else
{
while ((line[i] != '>') && (line[i] != '\0'))
i++;
if (line[i] == '>')
{
i++;
while (((line[i] == ' ') || (line[i] == '\n')) &&
(line[i] != '\0'))
i++;
if (line[i] == '\0')
break;
}
else if (line[i] == '\0')
break;
}
//
// *** block of text
//
default:
textout = true;
while (i < strlen(line))
{
switch (line[i])
{
case ' ':
appendchar(' ');
break;
case '\\':
if (line[++i] == 'n')
{
appendchar('\n');
// while(++i < strlen(line));
eol = true;
}
else
appendchar(line[i]);
break;
//
// *** interline definition (e.g. bold)
//
case '<':
parse_command(line+i, fd);
while(line[i] != '>')
i++;
break;
default:
appendchar(line[i]);
break;
}
i++;
} /* while */
if (textout && !eol)
appendchar(' ');
else if (eol)
eol = false;
break;
};
}
}
void TextView::appendchar(const char c)
{
TextInfo t;
//
// *** if defining hypertext, define TOC index
//
if (_ishyper)
t._tocindex = _tocindex;
else
t._tocindex = 255;
if ((_text->count() == 0) && (c != '\n'))
{
_characters->append(
new Discretionary(
PenaltyGood,
_partag->_fil_strut,
new VStrut(0),
nil,
_partag->_begin_par_strut
),
);
}
t._code = c;
_text->append(t);
switch (c)
{
//
// *** define space based on paragraph definition
//
case '\t':
_characters->append(
new Discretionary(0,
new HStrut(20), // _partag->_word_space,
_partag->_end_line_strut,
new Discretionary(0, _partag->_interline_glue,
_partag->_vfil_glue, nil, nil
),
_partag->_begin_line_strut
)
);
break;
case '\n':
_characters->append(
new Discretionary(
PenaltyGood,
_partag->_fil_strut,
_partag->_end_par_strut, // stretch after last line
new Discretionary(
0,
_partag->_interpar_glue, // space before a paragraph??
_partag->_vfil_glue, // space at bottom of a page
nil, // space after page break
nil // stetchability of page
),
_partag->_begin_par_strut // space before a paragraph
),
);
break;
//
// *** if hypertext, draw reversed
//
case ' ':
if (_ishyper)
_characters->append(
new Discretionary(0,
new Background(
new Character(' ', _fonttag->font(), _bg),_fg),
new HGlue(fil), nil, nil)
);
else
_characters->append(
new Discretionary(0,
_partag->_word_space,
_partag->_end_line_strut,
new Discretionary(
0,
_partag->_interline_glue,
_partag->_vfil_glue,
nil,
nil
),
_partag->_begin_line_strut
)
);
break;
default:
//
// *** if hypertext, draw reversed
//
if (_ishyper)
_characters->append(
new Background( new Character(c, _fonttag->font(), _bg), _fg)
);
else
_characters->append(new Character(c, _fonttag->font(), _fg));
break;
}
}
void TextView::draw(Canvas* c, const Allocation& a)const
{
MonoGlyph::draw(c, a);
}
boolean TextView::parse_command(char* line, FILE* fd)
{
char c;
char command[100];
char *gt;
int cindex;
boolean retval = false;
cindex = 0;
/*
* *** extract command
*/
sscanf(line+1, "%s", command);
gt = strchr(command, '>');
if (gt != NULL)
gt[0] = '\0';
/*
* *** if comment or MML version, ignore remainder
*/
if ((strcasecmp(command, "Comment") == 0) ||
(strcasecmp(command, "MML") == 0))
{
if (strchr(line, '>') == NULL)
{
while ((c = getc(fd)) != '>');
while ((c = getc(fd)) != '\n');
}
line[0] = '\0';
}
//
// *** insert Idraw figure
//
else if (strcasecmp(command, "Figure") == 0)
{
char fullname[256];
PSFigItem *psfig;
char *file;
char *endfile;
char creator[100];
file = strchr(line, '"')+1;
endfile = strrchr(line, '"');
endfile[0] = '\0';
if (_home != NULL)
{
strcpy(fullname, _home);
strcat(fullname, "/");
strcat(fullname, file);
}
else
strcpy(fullname, file);
psfig = new PSFigItem(fullname);
appendchar('\n');
_characters->append(
new LRBox(new HGlue(),
psfig->graphic(),
new HGlue()
)
);
retval = true;
}
else if (strcasecmp(command, "Include") == 0)
{
char fullname[256];
FILE *finclude;
char *file;
char *endfile;
file = strchr(line, '"');
endfile = strrchr(line, '"');
endfile[0] = '\0';
if (_home != NULL)
{
strcpy(fullname, _home);
strcat(fullname, "/");
strcat(fullname, file+1);
}
else
strcpy(fullname, file+1);
if ((finclude = fopen(fullname, "r")) != NULL)
read(finclude);
}
/*
* *** if definition, create definition and return
*/
else if (command[0] == '!')
define(line, fd);
else if (strcasecmp(command, "plain") == 0)
fontstyle("roman");
else if (strcasecmp(command, "bold") == 0)
fontstyle("bold");
else if (strncasecmp(command, "hyper", 5) == 0)
{
char *gt;
char tag[80];
_ishyper = true;
_tocindex = 255;
sscanf(line+strlen("hyper")+2, "%s", tag);
gt = strchr(tag, '>');
if (gt != nil)
gt[0] = '\0';
_tocindex = _parent->TOC(tag);
if (_tocindex == 255)
_ishyper = false;
}
else if (strncasecmp(command, "endhyp", 6) == 0)
_ishyper = false;
/*
* *** must be a previously defined user or system definition
*/
else
{
int i;
for (i = 0; i < _numpar; i++)
{
if (strcasecmp(command, parlist[i]->Id()) == 0)
{
_partag = parlist[i];
if (_partag->fonttag() != nil)
_fonttag = _partag->fonttag();
if (_partag->_hypertext)
_parent->updateTOC(fd, (int)_text->count());
return(true);
}
}
for (i = 0; i < _numfont; i++)
if (strcasecmp(command, fontlist[i]->Id()) == 0)
{
_fonttag = (FontTag*)fontlist[i];
return(retval);
}
}
return(retval);
}
void TextView::define(const char *line, FILE* fd)
{
char idbuf[40];
char tag[40];
int i;
//
// *** get tag name
//
sscanf(line, "%s", &tag);
i = strlen(tag);
while((line[i] == ' ') || (line[i] == '\t'))
i++;
sscanf(line+i, "%s", &idbuf);
//
// *** if already defined, ignore it
//
for (i = 0; i < _numpar; i++)
{
if (strcasecmp(parlist[i]->Id(), idbuf) == 0)
return;
}
for (i = 0; i < _numfont; i++)
{
if (strcasecmp(fontlist[i]->Id(), idbuf) == 0)
return;
}
if (strncmp(line+2, "DefineFont", 10) == 0)
fontlist[_numfont++] = new FontTag(line, fd);
else if (strncmp(line+2, "DefinePar", 9) == 0)
parlist[_numpar++] = new ParaTag(line, fd, this);
}
void TextView::fontstyle(const char* style)
{
char fontname[80];
char *stptr;
int i;
strcpy(fontname, _fonttag->Name());
//
// *** lookup font among defined font tags
//
if (((stptr = strchr(fontname, '-')) != NULL) &&
(strcmp(stptr+1, style) != NULL))
{
strcpy(stptr+1, style);
for (i = 0; i < _numfont; i++)
{
if ((strcmp((fontlist[i])->Name(), fontname) == 0) &&
(fontlist[i])->Points() == _fonttag->Points())
{
_fonttag = fontlist[i];
break;
}
}
}
}
void TextView::make_defaults()
{
_fonttag = new FontTag("deffont", 0);
_partag = new ParaTag("defpar");
fontlist[_numfont++] = _fonttag;
parlist[_numpar++] = _partag;
}
//
// *** generats postscript
//
void TextView::printout()
{
char psfile[256];
char *ext;
strcpy(psfile, _file);
ext = strrchr(psfile, '.');
if (ext != NULL)
ext[0] = '\0';
strcat(psfile, ".ps");
ofstream out(psfile);
Printer* ps = new Printer(&out);
//
// *** set size of page
//
const Allocation& a = _patch->allocation();
ps->prolog(psfile);
ps->resize(a.left(), a.bottom(), a.right(), a.top());
long current_page = 0;
long count = _pages->count();
for (long i = 1; i <= count/2; i++) {
ps->page(nil);
view_page((int)i);
_patch->print(ps, a);
}
_parent->page_to(1);
}