Commit 2695164b authored by Enrico Ros's avatar Enrico Ros

half link stuff foreported from head. Links are intercepted by our oDev and

stored as KPDFLink inside KPDFPage(s) :-). What we have now: links are
detected when hovering them on a page eve in multiple-pages-per-view mode.

svn path=/branches/kpdf_experiments/kdegraphics/kpdf/; revision=351190
parent 5b3dbe60
...@@ -20,7 +20,10 @@ ...@@ -20,7 +20,10 @@
#endif #endif
#include <kdebug.h> #include <kdebug.h>
#include <qpixmap.h>
#include <qimage.h>
#include "page.h"
#include "SplashBitmap.h" #include "SplashBitmap.h"
#include "TextOutputDev.h" #include "TextOutputDev.h"
#include "QOutputDev.h" #include "QOutputDev.h"
...@@ -36,11 +39,14 @@ KPDFOutputDev::KPDFOutputDev(SplashColor paperColor) ...@@ -36,11 +39,14 @@ KPDFOutputDev::KPDFOutputDev(SplashColor paperColor)
KPDFOutputDev::~KPDFOutputDev() KPDFOutputDev::~KPDFOutputDev()
{ {
QValueList< KPDFLink * >::iterator it = m_links.begin(), end = m_links.end();
for ( ; it != end; ++it )
delete *it;
delete m_pixmap; delete m_pixmap;
delete m_text; delete m_text;
} }
void KPDFOutputDev::setParams( int width, int height, bool generateText ) void KPDFOutputDev::setParams( int width, int height, bool genText, bool /*genLinks*/ )
{ {
m_pixmapWidth = width; m_pixmapWidth = width;
m_pixmapHeight = height; m_pixmapHeight = height;
...@@ -51,7 +57,12 @@ void KPDFOutputDev::setParams( int width, int height, bool generateText ) ...@@ -51,7 +57,12 @@ void KPDFOutputDev::setParams( int width, int height, bool generateText )
} }
delete m_text; delete m_text;
m_text = generateText ? new TextPage( gFalse ) : 0; m_text = genText ? new TextPage( gFalse ) : 0;
QValueList< KPDFLink * >::iterator it = m_links.begin(), end = m_links.end();
for ( ; it != end; ++it )
delete *it;
m_links.clear();
} }
QPixmap * KPDFOutputDev::takePixmap() QPixmap * KPDFOutputDev::takePixmap()
...@@ -68,6 +79,13 @@ TextPage * KPDFOutputDev::takeTextPage() ...@@ -68,6 +79,13 @@ TextPage * KPDFOutputDev::takeTextPage()
return text; return text;
} }
QValueList< KPDFLink * > KPDFOutputDev::takeLinks()
{
QValueList< KPDFLink * > linksCopy( m_links );
m_links.clear();
return linksCopy;
}
void KPDFOutputDev::startPage(int pageNum, GfxState *state) void KPDFOutputDev::startPage(int pageNum, GfxState *state)
{ {
m_pageNum = pageNum; m_pageNum = pageNum;
...@@ -102,14 +120,58 @@ void KPDFOutputDev::endPage() ...@@ -102,14 +120,58 @@ void KPDFOutputDev::endPage()
SplashOutputDev::startPage(0, NULL); SplashOutputDev::startPage(0, NULL);
} }
void KPDFOutputDev::drawLink(Link * /*l*/, Catalog */*catalog*/) void KPDFOutputDev::drawLink(Link * link, Catalog */*catalog*/)
{ {
/* double x1,y1, x2,y2; if ( !link->isOk() )
l->getRect( &x1,&y1, &x2,&y2 ); return;
LinkAction * a = l->getAction();
pri NOWARN ntf("LINK %x ok:%d t:%d rect:[%f,%f,%f,%f] \n", (uint)l, (int)l->isOk(), // create the new KPDFLink using transformed link coordinates
(int)a->getKind(), x1,y2, x2-x1, y2-y1 ); double x1, y1, x2, y2;
*/} link->getRect( &x1, &y1, &x2, &y2 );
int left, top, right, bottom;
cvtUserToDev( x1, y1, &left, &top );
cvtUserToDev( x2, y2, &right, &bottom );
KPDFLink * l = new KPDFLink( left, top, right, bottom );
// add the link to the vector container
m_links.push_back( l );
// set link action params processing (XPDF)LinkAction
LinkAction * a = link->getAction();
switch ( a->getKind() )
{
case actionGoTo: {
LinkGoTo * g = (LinkGoTo *) a;
GString * nd = g->getNamedDest();
LinkDest * d = g->getDest();
l->setLinkGoto( d ? d->copy() : 0, nd ? nd->getCString() : 0 );
} break;
case actionGoToR: {
LinkGoToR * g = (LinkGoToR *) a;
GString * nd = g->getNamedDest();
LinkDest * d = g->getDest();
l->setLinkGoto( d ? d->copy() : 0, nd ? nd->getCString() : 0, g->getFileName()->getCString() );
} break;
case actionLaunch:
l->setLinkExecute( ((LinkLaunch *)a)->getFileName()->getCString(),
((LinkLaunch *)a)->getParams()->getCString() );
break;
case actionURI:
l->setLinkURI( ((LinkURI *)a)->getURI()->getCString() );
break;
case actionNamed:
l->setLinkNamed( ((LinkNamed *)a)->getName()->getCString() );
break;
case actionMovie: {
LinkMovie * m = (LinkMovie *) a;
Ref * r = m->getAnnotRef();
l->setLinkMovie( r->num, r->gen, m->getTitle()->getCString() );
} break;
case actionUnknown:
// TODO Warn or not???
break;
}
}
void KPDFOutputDev::updateFont(GfxState *state) void KPDFOutputDev::updateFont(GfxState *state)
{ {
......
...@@ -19,13 +19,11 @@ ...@@ -19,13 +19,11 @@
#pragma interface #pragma interface
#endif #endif
#include <qimage.h>
#include "SplashOutputDev.h" #include "SplashOutputDev.h"
#include "Link.h" #include "Link.h"
class TextPage; class TextPage;
class KPDFPage; class KPDFLink;
/** /**
* @short A SplashOutputDev renderer that grabs text and links. * @short A SplashOutputDev renderer that grabs text and links.
...@@ -33,7 +31,7 @@ class KPDFPage; ...@@ -33,7 +31,7 @@ class KPDFPage;
* This output device: * This output device:
* - renders the page using SplashOutputDev (its parent) * - renders the page using SplashOutputDev (its parent)
* - harvests text into a textPage (for searching text) * - harvests text into a textPage (for searching text)
* - harvests links and set them to a KPDFPage * - harvests links and collect them
*/ */
class KPDFOutputDev : public SplashOutputDev class KPDFOutputDev : public SplashOutputDev
{ {
...@@ -42,11 +40,12 @@ public: ...@@ -42,11 +40,12 @@ public:
virtual ~KPDFOutputDev(); virtual ~KPDFOutputDev();
// to be called before PDFDoc->displayPage( thisclass, .. ) // to be called before PDFDoc->displayPage( thisclass, .. )
void setParams( int pixmapWidth, int pixmapHeight, bool generateText ); void setParams( int pixmapWidth, int pixmapHeight, bool generateTextpage, bool generateLinks );
// takes pointers out of the class (so deletion it's up to others) // takes pointers out of the class (so deletion it's up to others)
QPixmap * takePixmap(); QPixmap * takePixmap();
TextPage * takeTextPage(); TextPage * takeTextPage();
QValueList< KPDFLink * > takeLinks();
/** inherited from OutputDev */ /** inherited from OutputDev */
// Start a page. // Start a page.
...@@ -70,6 +69,9 @@ private: ...@@ -70,6 +69,9 @@ private:
// text page generated on demand // text page generated on demand
TextPage * m_text; TextPage * m_text;
// links generated on demand
QValueList< KPDFLink * > m_links;
}; };
...@@ -78,7 +80,8 @@ private: ...@@ -78,7 +80,8 @@ private:
* *
* This is the simplest OutputDev. It harvests text from currently * This is the simplest OutputDev. It harvests text from currently
* rendered page and provides a method for getting the TextPage. * rendered page and provides a method for getting the TextPage.
* Xpdf's textOutputDev can't return a textpage, unfortunately. * Xpdf's textOutputDev can't return a textpage, unfortunately, and
* KPDFOutputDev is too heavy for sucha a simple task.
*/ */
class KPDFTextDev : public OutputDev class KPDFTextDev : public OutputDev
{ {
......
...@@ -2,23 +2,28 @@ Personal Albert's list ...@@ -2,23 +2,28 @@ Personal Albert's list
-> make links functional (done in HEAD) -> make links functional (done in HEAD)
More items More items
-> new icons (contest at kde-look that will end in 2004-Oct-01) -> new icons (contest at kde-look that will end in 2004-Oct-XX)
-> screen editing (annotations): framework (BR67300,BR62793) -> screen editing (annotations): framework (BR67300,BR62793)
-> screen editing (annotations): tools (BR67300) -> screen editing (annotations): tools (BR67300)
-> export all text in plain_text/html -> export all text in plain_text/html
-> extract(export?) images -> extract(export?) images
-> implement history (mainly for actionNamed) -> implement history (mainly for actionNamed)
-> history as a toolbox child (collecting DOs's setPage calls)
-> zoom: fit text (with configurable margin) -> zoom: fit text (with configurable margin)
-> automatic online dictionaries / translators (BR80338) -> automatic online dictionaries / translators (BR80338)
-> session support: restoring page location (BR82589) -> session support: restoring page location (BR82589)
-> merge head copyright headers (by albert)
-> merge head xpdf changes for --enable-final (by adrian de groot/albert)
-> merge head support for show menubar in rmb (by albert)
-> wrong zoom buttons order (BR74248) (check consistancy with kdvi/kghostview/.. (not konq)) -> wrong zoom buttons order (BR74248) (check consistancy with kdvi/kghostview/.. (not konq))
Porting / In progress on the branch (first item comes first): Porting / In progress on the branch (first item comes first):
-> use a kconfigxt settings framework
-> fix keys/mouse in single/continous modes -> fix keys/mouse in single/continous modes
-> porting Albert's link following -> porting Albert's link following
-> minimize PageView's reLayout and requestPixmaps on changes -> minimize PageView's reLayout and requestPixmaps on changes
-> implementing async document generator using Albert's thread as the generation thread -> implementing async document generator using Albert's thread as the generation thread
-> reading aids (accessibility): mode: normal, invert, contrast, recolor bg/text -> reading aids (accessibility): mode: normal, invert, contrast, recolor bg/text (enhance links too)
Done (sorted by inv.time) Done (sorted by inv.time)
-> remake single page mode -> remake single page mode
......
...@@ -250,15 +250,19 @@ void KPDFDocument::requestPixmap( int id, uint page, int width, int height, bool ...@@ -250,15 +250,19 @@ void KPDFDocument::requestPixmap( int id, uint page, int width, int height, bool
// setup kpdf output device: text page is generated only if we are at 72dpi. // setup kpdf output device: text page is generated only if we are at 72dpi.
// since we can pre-generate the TextPage at the right res.. why not? // since we can pre-generate the TextPage at the right res.. why not?
bool genTextPage = !kp->hasSearchPage() && (width == kp->width()) && (height == kp->height()); bool genTextPage = !kp->hasSearchPage() && (width == kp->width()) && (height == kp->height());
d->kpdfOutputDev->setParams( width, height, genTextPage ); // generate links if rendering pages on pageview
bool genLinks = id == PAGEVIEW_ID;
d->kpdfOutputDev->setParams( width, height, genTextPage, genLinks );
d->docLock.lock(); d->docLock.lock();
d->pdfdoc->displayPage( d->kpdfOutputDev, page + 1, fakeDpiX, fakeDpiY, 0, true, false/*dolinks*/ ); d->pdfdoc->displayPage( d->kpdfOutputDev, page + 1, fakeDpiX, fakeDpiY, 0, true, genLinks );
d->docLock.unlock(); d->docLock.unlock();
kp->setPixmap( id, d->kpdfOutputDev->takePixmap() ); kp->setPixmap( id, d->kpdfOutputDev->takePixmap() );
if ( genTextPage ) if ( genTextPage )
kp->setSearchPage( d->kpdfOutputDev->takeTextPage() ); kp->setSearchPage( d->kpdfOutputDev->takeTextPage() );
if ( genLinks )
kp->setLinks( d->kpdfOutputDev->takeLinks() );
d->observers[id]->notifyPixmapChanged( page ); d->observers[id]->notifyPixmapChanged( page );
} }
...@@ -294,7 +298,7 @@ void KPDFDocument::slotSetFilter( const QString & pattern, bool keepCase ) ...@@ -294,7 +298,7 @@ void KPDFDocument::slotSetFilter( const QString & pattern, bool keepCase )
void KPDFDocument::slotBookmarkPage( int page, bool on ) void KPDFDocument::slotBookmarkPage( int page, bool on )
{ {
KPDFPage * p = ( page < d->pages.count() ) ? d->pages[page] : 0; KPDFPage * p = ( page < (int)d->pages.count() ) ? d->pages[page] : 0;
if ( p ) if ( p )
{ {
p->bookmark( on ); p->bookmark( on );
......
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
<Action name="zoom_fit_width"/> <Action name="zoom_fit_width"/>
<Action name="zoom_fit_page"/> <Action name="zoom_fit_page"/>
<Separator/> <Separator/>
<Action name="view_continous"/>
<Action name="view_twopages"/> <Action name="view_twopages"/>
<Action name="view_continous"/>
</Menu> </Menu>
<Menu name="go"><text>&amp;Go</text> <Menu name="go"><text>&amp;Go</text>
<Action name="first_page"/> <Action name="first_page"/>
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
<!--Action name="zoom_fit_page"/--> <!--Action name="zoom_fit_page"/-->
<Merge/> <Merge/>
<Separator/> <Separator/>
<Action name="view_continous"/>
<Action name="view_twopages"/> <Action name="view_twopages"/>
<Action name="view_continous"/>
<Separator/> <Separator/>
<Action name="mouse_drag"/> <Action name="mouse_drag"/>
<Action name="mouse_select"/> <Action name="mouse_select"/>
......
...@@ -15,7 +15,11 @@ ...@@ -15,7 +15,11 @@
#include <qpainter.h> #include <qpainter.h>
#include <qmap.h> #include <qmap.h>
// system includes
#include <string.h>
// local includes // local includes
#include "Link.h"
#include "TextOutputDev.h" #include "TextOutputDev.h"
#include "page.h" #include "page.h"
...@@ -34,6 +38,9 @@ KPDFPage::~KPDFPage() ...@@ -34,6 +38,9 @@ KPDFPage::~KPDFPage()
QMap<int,QPixmap *>::iterator it = m_pixmaps.begin(), end = m_pixmaps.end(); QMap<int,QPixmap *>::iterator it = m_pixmaps.begin(), end = m_pixmaps.end();
for ( ; it != end; ++it ) for ( ; it != end; ++it )
delete *it; delete *it;
QValueList< KPDFLink * >::iterator lIt = m_links.begin(), lEnd = m_links.end();
for ( ; lIt != lEnd; ++lIt )
delete *lIt;
delete m_text; delete m_text;
} }
...@@ -53,9 +60,13 @@ bool KPDFPage::hasSearchPage() const ...@@ -53,9 +60,13 @@ bool KPDFPage::hasSearchPage() const
bool KPDFPage::hasLink( int mouseX, int mouseY ) const bool KPDFPage::hasLink( int mouseX, int mouseY ) const
{ {
//TODO this. if ( m_links.count() < 0 )
//Sample implementation using a small rect as 'active' link zone return false;
return QRect( 20,20, 100,50 ).contains( mouseX, mouseY ); QValueList< KPDFLink * >::const_iterator it = m_links.begin(), end = m_links.end();
for ( ; it != end; ++it )
if ( (*it)->contains( mouseX, mouseY ) )
return true;
return false;
} }
// BEGIN commands (paint / search) // BEGIN commands (paint / search)
...@@ -169,12 +180,96 @@ void KPDFPage::setSearchPage( TextPage * tp ) ...@@ -169,12 +180,96 @@ void KPDFPage::setSearchPage( TextPage * tp )
m_text = tp; m_text = tp;
} }
/* void KPDFPage::setLinks( const QValueList<KPDFLink *> links )
void KPDFPage::setLinks( ..SomeStruct.. ) {
{ //TODO this QValueList< KPDFLink * >::iterator it = m_links.begin(), end = m_links.end();
for ( ; it != end; ++it )
delete *it;
m_links = links;
} }
/*
void KPDFPage::setPixmapOverlayNotations( ..DOMdescription.. ) void KPDFPage::setPixmapOverlayNotations( ..DOMdescription.. )
{ //TODO this { //TODO this
} }
*/ */
KPDFLink::KPDFLink( int l, int t, int r, int b )
: m_type( Unknown ), m_dest( 0 ), m_destNamed( 0 ),
m_fileName( 0 ), m_parameters( 0 ), m_uri( 0 )
{
// assign coordinates swapping them if negative width or height
x_min = r > l ? l : r;
x_max = r > l ? r : l;
y_min = b > t ? t : b;
y_max = b > t ? b : t;
}
KPDFLink::~KPDFLink()
{
delete m_dest;
delete [] m_destNamed;
delete [] m_fileName;
delete [] m_parameters;
delete [] m_uri;
}
void KPDFLink::setLinkGoto( LinkDest * d, const char * n, const char * file )
{
m_type = Goto;
delete m_dest;
m_dest = d;
copyString( m_destNamed, n );
copyString( m_fileName, file );
}
void KPDFLink::setLinkExecute( const char * file, const char * par )
{
m_type = Execute;
copyString( m_fileName, file );
copyString( m_parameters, par );
}
void KPDFLink::setLinkNamed( const char * name )
{
m_type = Action;
copyString( m_uri, name );
}
void KPDFLink::setLinkURI( const char * uri )
{
m_type = URI;
copyString( m_uri, uri );
}
void KPDFLink::setLinkMovie( int ref_num, int ref_gen, const char * title )
{
m_type = Movie;
m_refNum = ref_num;
m_refGen = ref_gen;
copyString( m_uri, title );
}
KPDFLink::LinkType KPDFLink::type() const
{
return m_type;
}
bool KPDFLink::contains( int x, int y ) const
{
return (x > x_min) && (x < x_max) && (y > y_min) && (y < y_max);
}
void KPDFLink::copyString( char * dest, const char * src )
{
if ( dest )
delete [] dest;
dest = 0;
if ( src )
{
dest = new char[ strlen(src) + 1 ];
strcpy( dest, src );
}
}
...@@ -10,11 +10,14 @@ ...@@ -10,11 +10,14 @@
#ifndef _KPDF_PAGE_H_ #ifndef _KPDF_PAGE_H_
#define _KPDF_PAGE_H_ #define _KPDF_PAGE_H_
#include <qmap.h>
#include <qvaluelist.h>
class QPainter; class QPainter;
class QPixmap; class QPixmap;
//class QString;
//class QRect;
class TextPage; class TextPage;
class LinkDest;
class KPDFLink;
/** /**
* @short Collector for all the data belonging to a page. * @short Collector for all the data belonging to a page.
...@@ -25,15 +28,13 @@ class TextPage; ...@@ -25,15 +28,13 @@ class TextPage;
* *
* Note: All objects passed to this class will be destoryed on class deletion. * Note: All objects passed to this class will be destoryed on class deletion.
*/ */
// ### HACK : this structure is under big changes ###
class KPDFPage class KPDFPage
{ {
public: public:
KPDFPage( int number, float width, float height, int rotation ); KPDFPage( int number, float width, float height, int rotation );
~KPDFPage(); ~KPDFPage();
// query properties (const read-only methods) // query properties and draw (const read-only methods)
uint number() const { return m_number; } uint number() const { return m_number; }
float width() const { return m_width; } float width() const { return m_width; }
float height() const { return m_height; } float height() const { return m_height; }
...@@ -44,17 +45,17 @@ public: ...@@ -44,17 +45,17 @@ public:
bool hasPixmap( int id, int width, int height ) const; bool hasPixmap( int id, int width, int height ) const;
bool hasSearchPage() const; bool hasSearchPage() const;
bool hasLink( int mouseX, int mouseY ) const; bool hasLink( int mouseX, int mouseY ) const;
// commands
void drawPixmap( int id, QPainter * p, const QRect & rect, int width, int height ) const; void drawPixmap( int id, QPainter * p, const QRect & rect, int width, int height ) const;
// commands (not const methods caled by KPDFDocument)
bool hasText( const QString & text, bool strictCase, bool fromTop ); bool hasText( const QString & text, bool strictCase, bool fromTop );
void hilightLastSearch( bool enabled ); void hilightLastSearch( bool enabled );
void bookmark( bool enabled ); void bookmark( bool enabled );
// set page contents // set page contents (not const methods caled by KPDFDocument)
void setPixmap( int id, QPixmap * pixmap ); void setPixmap( int id, QPixmap * pixmap );
void setSearchPage( TextPage * text ); void setSearchPage( TextPage * text );
/*void setLinks( ..SomeStruct.. ); or (better): */ void setLinks( const QValueList<KPDFLink *> links );
/*void setPixmapOverlayNotations( ..DOMdescription.. );*/ /*void setPixmapOverlayNotations( ..DOMdescription.. );*/
private: private:
...@@ -63,26 +64,56 @@ private: ...@@ -63,26 +64,56 @@ private:
bool m_hilighting, m_bookmarking; bool m_hilighting, m_bookmarking;
double m_sLeft, m_sTop, m_sRight, m_sBottom; double m_sLeft, m_sTop, m_sRight, m_sBottom;
QMap<int,QPixmap *> m_pixmaps; QMap< int, QPixmap * > m_pixmaps;
TextPage * m_text; TextPage * m_text;
QValueList< KPDFLink * > m_links;
}; };
/*
/**
* @short Encapsulates data that describes a link.
*
* There are many types of PDF links, here we provide accessors to set the
* link to be of the given type. Other functions are for asking if a point
* is inside the link rect (in displayed page coordinates).
* KPDFLinks are created by the KPDFOutputDevice then stored and deleted
* inside the referring KPDFPage.
* Note: this structure is similar to XPDF LinkAction and its hieracy, but
* is needed for storing data inside pages, since XPDF's PDFDoc deletes
* Links objects when changing page (and we need persistant storage).
*/
class KPDFLink class KPDFLink
{ {
public: public:
enum LinkType { Goto, Execute, Action, URI, Movie }; KPDFLink( int left, int top, int right, int bottom );
~KPDFLink();