Implemented Hyperlinks

svn path=/trunk/kdegraphics/kdvi/; revision=52871
remotes/origin/kdvi-2.0
Stefan Kebekus 26 years ago
parent df505bb0bc
commit 55dc43bff4
  1. 31
      AUTHORS
  2. 13
      TODO
  3. 17
      dvi_init.cpp
  4. 92
      dviwin.cpp
  5. 26
      dviwin.h
  6. 16
      kdvi_multipage.cpp
  7. 8
      kdvi_multipage.h
  8. 216
      special.cpp
  9. 1
      version.h
  10. 7
      vf.cpp

@ -1,12 +1,24 @@
This program, xdvik, was modified by kb@cs.umb.edu from Paul
Vojta's xdvi distribution for common path searching, GNU-style
configuration, etc. Send bug reports to tex-k@cs.umb.edu, not to Paul.
See the README for more info.
The programm KDVI is based on the dvi-previewer xdvik, See below. KDVI
was written by Markku Hihnala with the help of many
collaborators. Later KDVI became a plug-in to KViewShell and Stefan
Kebekus re-implemented parts of the program. The current version of
KDVI shares a substantial amount of code with xdvi, not not very much
with the first versions of KDVI.
------------------------------------------------------------------------------
AUTHORS OF xdvik
================
This program, xdvik, was modified by kb@cs.umb.edu from Paul Vojta's
xdvi distribution for common path searching, GNU-style configuration,
etc. Send bug reports to tex-k@cs.umb.edu, not to Paul. See the
README for more info.
Here are the credits for the original xdvi program:
This program is the combined work of many people, including but not
restricted to:
This program is the combined work of many people, including but not restricted to:
Eric Cooper, CMU
Bob Scheifler, MIT LCS
Paal Kvamme, Norwegian Institute of Technology
@ -16,9 +28,10 @@ restricted to:
Jeffrey Lee, U of Toronto
Donald Richardson, Clarkson Univ.
In addition to the various comp.sources.x archives, current versions of this
program (the original xdvi, not xdvik) can also be obtained via
anonymous ftp from the following location:
In addition to the various comp.sources.x archives, current versions
of this program (the original xdvi, not xdvik) can also be obtained
via anonymous ftp from the following location:
export.lcs.mit.edu [18.30.0.212] file contrib/xdvi.tar.Z
To ease the load on expo, you may also check other X archives, for example:
gatekeeper.dec.com [16.1.0.2] file pub/X11/contrib/xdvi.shar.Z

13
TODO

@ -3,12 +3,13 @@ ToDo-List for kdvi
URGENT
o implement SaveAs
o Fonts should be free when file is reloaded and the fonts are no longer needed
o Optionrequester: changes (e.g. PostScript on/off) are not applied until restart of the program.
o Re-Implement PostScript specials, including proper handling of header (="bang")
specials.
o Optionrequester: Hypertext on/off, Warnings on/off
o Proper Error handling with throw/catch
@ -18,12 +19,9 @@ o Document the technical specs.
o Bugfixing
o psgs should remove tmp-files
o epsf specials should forward keywords to the postscript file.
o psgs should use and remove tmp-files
o Support for Hyperlatex specials (xxx.lanl.gov, probably the world's largest
collection of dvi-files, uses Hyperlatex for every file!)
o kvieshell should change pageno when clicking on internal hyperlinks
HIGHLY DESIRABLE
@ -51,3 +49,4 @@ o Two page view
o Support for even more TeX specials
o Popup-Window to inform the user when Fonts are generated
o Search option
o dynamical storage allocation for hyperlinks (see dviwin.h)

@ -249,7 +249,6 @@ static void process_preamble()
magnification = four(dvi_file);
dimconv = (((double) numerator * magnification) / ((double) denominator * 1000.));
dimconv = dimconv * (((long) pixels_per_inch)<<16) / 254000;
tpic_conv = pixels_per_inch * magnification / 1000000.0;
k = one(dvi_file);
Fread(job_id, sizeof(char), (int) k, dvi_file);
job_id[k] = '\0';
@ -393,21 +392,27 @@ Boolean dviWindow::init_dvi_file()
PostScriptDirectory = new QVector<QString>(total_pages+1);
PostScriptDirectory->setAutoDelete(TRUE);
PostScriptHeaderString.truncate(0);
for(int i=0; i<total_pages; i++) {
// We will also generate a list of hyperlink-anchors in the
// document. So declare the existing list empty.
numAnchors = 0;
int save_current_page = current_page;
for(current_page=0; current_page<total_pages; current_page++) {
PostScriptOutPutString = new QString();
(void) lseek(fileno(dvi_file), page_offset[i], SEEK_SET);
(void) lseek(fileno(dvi_file), page_offset[current_page], SEEK_SET);
bzero((char *) &currinf.data, sizeof(currinf.data));
currinf.fonttable = tn_table;
currinf.end = dvi_buffer;
currinf.pos = dvi_buffer;
currinf._virtual = NULL;
draw_part(current_frame = &frame0, dimconv);
PostScriptDirectory->insert(i,PostScriptOutPutString);
PostScriptDirectory->insert(current_page,PostScriptOutPutString);
}
PostScriptOutPutString = NULL;
current_page = save_current_page;
return True;
}

@ -15,11 +15,13 @@
#include <qpaintdevice.h>
#include <qfileinfo.h>
#include <qimage.h>
#include <qurl.h>
#include <kapp.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <klocale.h>
#include <kprocess.h>
#include "dviwin.h"
#include "optiondialog.h"
@ -38,11 +40,10 @@ struct WindowRec currwin = {(Window) 0, 3, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0};
extern struct WindowRec alt;
struct drawinf currinf;
int _debug;
//int _debug;
char *prog;
Display *DISP;
int min_x, max_x, min_y, max_y;
double tpic_conv;
//int min_x, max_x, min_y, max_y;
struct font *font_head = NULL;
char *dvi_name = NULL;
int total_pages;
@ -52,9 +53,6 @@ const char *dvi_oops_msg; /* error message */
double dimconv;
int n_files_left; /* for LRU closing of fonts */
jmp_buf dvi_env; /* mechanism to communicate dvi file errors */
long magnification;
unsigned int page_w, page_h;
long *page_offset;
QIntDict<struct font> tn_table;
@ -68,20 +66,28 @@ Screen *SCRN;
int _pixels_per_inch;
_Xconst char *_paper;
// The following are really used
long magnification;
unsigned int page_w;
unsigned int page_h;
// end of "really used"
extern char * prog;
extern char * dvi_name;
extern FILE * dvi_file;
extern int n_files_left;
extern int min_x;
extern int min_y;
extern int max_x;
extern int max_y;
//extern int min_x;
//extern int min_y;
//extern int max_x;
//extern int max_y;
extern unsigned int page_w, page_h;
extern int current_page;
extern int total_pages;
extern Display * DISP;
extern Screen * SCRN;
Window mainwin;
Window mainwin;
int useAlpha;
void draw_page(void);
@ -200,25 +206,25 @@ int dviWindow::makePK()
void dviWindow::setFontPath( const char *s )
{
if (!ChangesPossible)
KMessageBox::sorry( this,
if (!ChangesPossible)
KMessageBox::sorry( this,
i18n("The change in font path will be effective\n"
"only after you start kdvi again!"));
FontPath = s;
"only after you start kdvi again!"));
FontPath = s;
}
const char * dviWindow::fontPath()
{
return FontPath;
return FontPath;
}
void dviWindow::setMetafontMode( const char *mfm )
{
if (!ChangesPossible)
KMessageBox::sorry( this,
if (!ChangesPossible)
KMessageBox::sorry( this,
i18n("The change in Metafont mode will be effective\n"
"only after you start kdvi again!") );
MetafontMode = mfm;
"only after you start kdvi again!") );
MetafontMode = mfm;
}
const char * dviWindow::metafontMode()
@ -252,7 +258,7 @@ void dviWindow::setResolution( int bdpi )
int dviWindow::resolution()
{
return basedpi;
return basedpi;
}
@ -302,10 +308,12 @@ void dviWindow::drawPage()
return;
}
/*@@@
min_x = 0;
min_y = 0;
max_x = page_w;
max_y = page_h;
*/
if ( !pixmap )
return;
@ -343,8 +351,10 @@ bool dviWindow::correctDVI()
if ( n < 134 ) // Too short for a dvi file
return FALSE;
f.at( n-4 );
char test[4];
unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
if ( f.readBlock( test, 4 )<4 || strncmp( test, (char *) trailer, 4 ) )
return FALSE;
// We suppose now that the dvi file is complete and OK
@ -374,12 +384,12 @@ void dviWindow::changePageSize()
void dviWindow::setFile( const char *fname )
{
if (ChangesPossible){
initDVI();
}
filename = fname;
dvi_name = 0;
drawPage();
if (ChangesPossible){
initDVI();
}
filename = fname;
dvi_name = 0;
drawPage();
}
@ -429,10 +439,36 @@ void dviWindow::paintEvent(QPaintEvent *ev)
void dviWindow::mousePressEvent ( QMouseEvent * e )
{
#ifdef DEBUG_SPECIAL
kdDebug() << "mouse event" << endl;
#endif
for(int i=0; i<num_of_used_hyperlinks; i++) {
if (hyperLinkList[i].box.contains(e->pos())) {
kdDebug() << "hit:" << hyperLinkList[i].linkText << endl;
if (hyperLinkList[i].linkText[0] == '#' ) {
#ifdef DEBUG_SPECIAL
kdDebug() << "hit: local link to " << hyperLinkList[i].linkText << endl;
#endif
QString locallink = hyperLinkList[i].linkText.mid(1); // Drop the '#' at the beginning
for(int j=0; j<numAnchors; j++) {
if (locallink.compare(AnchorList_String[j]) == 0) {
// @@@Currently there is no-one listening. Make sure
// kviewshell has a slot for this.
emit(request_goto_page(AnchorList_Page[j], AnchorList_Vert[j]));
break;
}
}
} else {
#ifdef DEBUG_SPECIAL
kdDebug() << "hit: external link to " << hyperLinkList[i].linkText << endl;
#endif
QUrl DVI_Url(filename);
QUrl Link_Url(DVI_Url, hyperLinkList[i].linkText, TRUE );
KShellProcess proc;
proc << "kfmclient openURL " << Link_Url.toString();
proc.start(KProcess::Block);
//@@@ Set up a warning requester if the command failed?
}
break;
}
}

@ -20,6 +20,9 @@
// max. number of hyperlinks per page. This should late be replaced by
// a dynamic allocation scheme.
#define MAX_HYPERLINKS 200
// max. number of anchors per document. This should late be replaced by
// a dynamic allocation scheme.
#define MAX_ANCHORS 300
class DVI_Hyperlink {
public:
@ -77,18 +80,21 @@ public:
void header_special(QString cp);
void html_href_special(QString cp);
void html_anchor_end(void);
void html_anchor_special(QString cp);
void drawPage();
bool correctDVI();
public slots:
void setFile(const char *fname);
void gotoPage(int page);
// void setZoom(int zoom);
void setZoom(double zoom);
double zoom() { return _zoom; };
void setZoom(double zoom);
double zoom() { return _zoom; };
void drawPage();
bool correctDVI();
signals:
/// Emitted to indicate that a hyperlink has been clicked on, and
//that the widget requests that the controlling program goes to the
//page and the coordinates specified.
void request_goto_page(int page, int y);
protected:
void paintEvent(QPaintEvent *ev);
@ -127,6 +133,12 @@ private:
DVI_Hyperlink hyperLinkList[MAX_HYPERLINKS];
int num_of_used_hyperlinks;
// List of anchors in a document
QString AnchorList_String[MAX_ANCHORS];
unsigned int AnchorList_Page[MAX_ANCHORS];
double AnchorList_Vert[MAX_ANCHORS];
int numAnchors;
void initDVI();
void changePageSize();
QString filename;

@ -69,12 +69,13 @@ KDVIMultiPage::KDVIMultiPage(QWidget *parent, const char *name)
preferencesChanged();
new KAction(i18n("&DVI Options"), 0, this,
SLOT(doSettings()), actionCollection(),
"settings_dvi");
SLOT(doSettings()), actionCollection(),
"settings_dvi");
setXMLFile("kdvi_part.rc");
scrollView()->addChild(window);
connect(window, SIGNAL(request_goto_page(int, int)), this, SLOT(goto_page(int, int) ) );
readSettings();
}
@ -127,6 +128,15 @@ bool KDVIMultiPage::gotoPage(int page)
return true;
}
void KDVIMultiPage::goto_page(int page, int y)
{
window->gotoPage(page+1);
scrollView()->ensureVisible(scrollView()->width()/2, (int)(y/window->zoom()) );
emit previewChanged(true);
emit moved_to_page(page);
}
double KDVIMultiPage::setZoom(double zoom)
{

@ -84,18 +84,22 @@ public:
virtual void reload();
signals:
/// emitted to indicate the number of pages in the file
void numberOfPages(int nr);
/// emitted to indicate that KDVIMultiPage has jumped to a different
//page without being asked to by the kviewshell, i.e. because the
//user clicked on a hyperlink.
void moved_to_page(int nr);
protected slots:
void doSettings();
void preferencesChanged();
void goto_page(int page, int y);
private:

@ -1,121 +1,42 @@
#define DEBUG_SPECIAL
// special.cpp
// Methods for dviwin which deal with "\special" commands found in the
// DVI file
// Copyright 2000, Stefan Kebekus (stefan.kebekus@uni-bayreuth.de).
#include <qfile.h>
#include <kdebug.h>
#include "dviwin.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "oconfig.h"
extern "C" {
#define HAVE_PROTOTYPES
#include <kpathsea/c-ctype.h>
#include <kpathsea/c-fopen.h>
#include <kpathsea/c-proto.h>
#include <kpathsea/types.h>
#include <kpathsea/tex-file.h>
#include <kpathsea/line.h>
}
extern QPainter foreGroundPaint;
extern double xres;
void draw_bbox()
void dviWindow::html_anchor_special(QString cp)
{
#ifdef auskommentiert
if (bbox_valid) {
put_border(PXL_H - currwin.base_x,
PXL_V - currwin.base_y - bbox_voffset,
bbox_width, bbox_height);
bbox_valid = False;
}
if (PostScriptOutPutString != NULL) { // only during scanning, not during rendering
cp.truncate(cp.find('"'));
#ifdef DEBUG_SPECIAL
kdDebug() << "HTML-special, anchor " << cp.latin1() << endl;
kdDebug() << "page " << current_page << endl;
#endif
AnchorList_String[numAnchors] = cp;
AnchorList_Page[numAnchors] = current_page;
AnchorList_Vert[numAnchors] = (DVI_V*xres)/(65536*basedpi); // multiply with zoom to get pixel coords
if (numAnchors < MAX_ANCHORS-2)
numAnchors++;
}
}
#ifdef auskommentiert
/* If FILENAME starts with a left quote, set *DECOMPRESS to 1 and return
the rest of FILENAME. Otherwise, look up FILENAME along the usual
path for figure files, set *DECOMPRESS to 0, and return the result
(NULL if can't find the file). */
static string find_fig_file (char *filename)
{
char *name;
name = kpse_find_pict (filename);
if (!name)
kdError() << "Cannot open PS file " << filename << endl;
return name;
}
/* If DECOMPRESS is zero, pass NAME to the drawfile proc. But if
DECOMPRESS is nonzero, open a pipe to it and pass the resulting
output to the drawraw proc (in chunks). */
static void draw_file (psprocs psp, char *name)
{
kDebugInfo(DEBUG, 4300, "draw file %s",name);
psp.drawfile (name);
}
static void psfig_special(char *cp)
{
kDebugInfo("PSFig special: %s",cp);
char *filename;
int raww, rawh;
if (strncmp(cp, ":[begin]", 8) == 0) {
cp += 8;
bbox_valid = False;
if (sscanf(cp,"%d %d\n", &raww, &rawh) >= 2) {
bbox_valid = True;
bbox_width = pixel_conv(spell_conv(raww));
bbox_height = pixel_conv(spell_conv(rawh));
bbox_voffset = 0;
}
if (currwin.win == mane.win)
psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,cp);
} else
if (strncmp(cp, " plotfile ", 10) == 0) {
cp += 10;
while (isspace(*cp)) cp++;
for (filename = cp; !isspace(*cp); ++cp);
*cp = '\0';
{
char *name = find_fig_file (filename);
if (name && currwin.win == mane.win) {
draw_file(psp, name);
if (name != filename)
free (name);
}
}
} else
if (strncmp(cp, ":[end]", 6) == 0) {
cp += 6;
if (currwin.win == mane.win)
psp.drawend(cp);
bbox_valid = False;
} else { /* I am going to send some raw postscript stuff */
if (*cp == ':')
++cp; /* skip second colon in ps:: */
if (currwin.win == mane.win) {
/* It's drawbegin that initializes the ps process, so make
sure it's started up. */
psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, "");
psp.drawend("");
psp.drawraw(cp);
}
}
}
#endif
void dviWindow::html_href_special(QString cp)
{
cp.truncate(cp.find('"'));
@ -148,13 +69,13 @@ void dviWindow::header_special(QString cp)
kdDebug() << "PostScript-special, header " << cp.latin1() << endl;
#endif
if (PostScriptOutPutString) {
if (PostScriptOutPutString && QFile::exists(cp)) {
PostScriptHeaderString.append( QString(" (%1) run\n").arg(cp) );
}
}
static void parse_special_argument(QString strg, char *argument_name, int *variable)
static void parse_special_argument(QString strg, const char *argument_name, int *variable)
{
bool OK;
@ -174,7 +95,9 @@ static void parse_special_argument(QString strg, char *argument_name, int *varia
void dviWindow::epsf_special(QString cp)
{
#ifdef DEBUG_SPECIAL
kdError() << "epsf-special: psfile=" << cp <<endl;
#endif
QString include_command = cp.simplifyWhiteSpace();
@ -182,12 +105,6 @@ void dviWindow::epsf_special(QString cp)
// filename. Figure out what the filename is and stow it away
QString filename = include_command;
filename.truncate(filename.find(' '));
char *name = kpse_find_pict(filename.local8Bit());
if (name != NULL) {
filename = name;
free(name);
} else
filename.truncate(0);
//
// Now parse the arguments.
@ -198,7 +115,6 @@ void dviWindow::epsf_special(QString cp)
int ury = 0;
int rwi = 0;
int rhi = 0;
int hoffset = 0;
// just to avoid ambiguities; the filename could contain keywords
include_command = include_command.mid(include_command.find(' '));
@ -210,37 +126,53 @@ void dviWindow::epsf_special(QString cp)
parse_special_argument(include_command, "rwi=", &rwi);
parse_special_argument(include_command, "rhi=", &rhi);
// calculate the size of the bounding box
double bbox_width = urx - llx;
double bbox_height = lly - ury;
if ((rwi != 0)&&(bbox_width != 0)) {
bbox_height = bbox_height*rwi/bbox_width;
bbox_width = rwi;
}
if ((rhi != 0)&&(bbox_height != 0)) {
bbox_height = rhi;
bbox_width = bbox_width*rhi/bbox_height;
}
bbox_width *= 0.1 * dimconv / shrink_factor;
bbox_height *= 0.1 * dimconv / shrink_factor;
if (PostScriptOutPutString) {
PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(DVI_H/65536 - 300).arg(DVI_V/65536 - 520) );
PostScriptOutPutString->append( "@beginspecial @setspecial \n" );
PostScriptOutPutString->append( QString(" (%1) run\n").arg(filename) );
PostScriptOutPutString->append( "@endspecial \n" );
if (QFile::exists(filename)) {
PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(DVI_H/65536 - 300).arg(DVI_V/65536 - 520) );
PostScriptOutPutString->append( "@beginspecial " );
PostScriptOutPutString->append( QString(" %1 @llx").arg(llx) );
PostScriptOutPutString->append( QString(" %1 @lly").arg(lly) );
PostScriptOutPutString->append( QString(" %1 @urx").arg(urx) );
PostScriptOutPutString->append( QString(" %1 @ury").arg(ury) );
if (rwi != 0)
PostScriptOutPutString->append( QString(" %1 @rwi").arg(rwi) );
if (rhi != 0)
PostScriptOutPutString->append( QString(" %1 @rhi").arg(rwi) );
PostScriptOutPutString->append( " @setspecial \n" );
PostScriptOutPutString->append( QString(" (%1) run\n").arg(filename) );
PostScriptOutPutString->append( "@endspecial \n" );
}
} else {
kdDebug() << "_postscript " << _postscript << endl;
if (!_postscript) {
// Don't show PostScript, just draw to bounding box
if (!_postscript || !QFile::exists(filename)) {
// Don't show PostScript, just draw the bounding box
// For this, calculate the size of the bounding box in Pixels
double bbox_width = urx - llx;
double bbox_height = lly - ury;
if ((rwi != 0)&&(bbox_width != 0)) {
bbox_height = bbox_height*rwi/bbox_width;
bbox_width = rwi;
}
if ((rhi != 0)&&(bbox_height != 0)) {
bbox_height = rhi;
bbox_width = bbox_width*rhi/bbox_height;
}
bbox_width *= 0.1 * dimconv / shrink_factor;
bbox_height *= 0.1 * dimconv / shrink_factor;
QRect bbox(PXL_H - currwin.base_x, PXL_V - currwin.base_y, (int)bbox_width, (int)bbox_height);
foreGroundPaint.setBrush(Qt::lightGray);
foreGroundPaint.setPen (Qt::black);
foreGroundPaint.drawRoundRect(bbox, 1, 1);
foreGroundPaint.drawText (bbox, (int)(Qt::AlignCenter), filename, -1, &bbox);
if (QFile::exists(filename))
foreGroundPaint.setBrush(Qt::lightGray);
else
foreGroundPaint.setBrush(Qt::red);
foreGroundPaint.setPen(Qt::black);
foreGroundPaint.drawRoundRect(bbox, 2, 2);
if (QFile::exists(filename))
foreGroundPaint.drawText (bbox, (int)(Qt::AlignCenter), filename, -1, &bbox);
else
foreGroundPaint.drawText (bbox, (int)(Qt::AlignCenter),
QString("File not found:\n %1").arg(filename), -1, &bbox);
}
}
return;
@ -249,7 +181,7 @@ void dviWindow::epsf_special(QString cp)
void dviWindow::bang_special(QString cp)
{
#ifdef DEBUG_SPECIAL
// kdDebug() << "PostScript-special, literal header " << cp.latin1() << endl;
kdDebug() << "PostScript-special, literal header " << cp.latin1() << endl;
#endif
if (currwin.win == mane.win && PostScriptOutPutString) {
@ -316,6 +248,12 @@ void dviWindow::applicationDoSpecial(char *cp)
return;
}
// HTML anchor special
if (special_command.find("html:<A name=") == 0) {
html_anchor_special(special_command.mid(14));
return;
}
kdError() << "special \"" << cp << "\" not implemented" << endl;
return;
}

@ -1 +0,0 @@
#define KDVI_VERSION "0.4.3"

@ -23,7 +23,6 @@
* SUCH DAMAGE.
*/
#define DEBUG 0
#include <kdebug.h>
#include <stdio.h>
@ -64,16 +63,18 @@ extern void oops(const char *message, ...);
void font::read_VF_index(void)
{
#ifdef DEBUG_FONTS
kdDebug() << "read_VF_index" << endl;
#endif
FILE *VF_file = file;
unsigned char cmnd;
unsigned char *avail, *availend; /* available space for macros */
flags |= FONT_VIRTUAL;
set_char_p = &dviWindow::set_vf_char;
#ifdef DEBUG_FONTS
kdDebug() << "Reading VF pixel file " << filename << endl;
#endif
// Read preamble.
Fseek(VF_file, (long) one(VF_file), 1); /* skip comment */
long file_checksum = four(VF_file);

Loading…
Cancel
Save