Commit 2a3f35ac authored by Enrico Ros's avatar Enrico Ros
Browse files

Fixed broken link following (if not in external document).

 Normalized [0..1] every object attached to page.
Fixed find-ahead (didn't loop after last page).

svn path=/trunk/kdegraphics/kpdf/; revision=387447
parent bcf32aaf
...@@ -81,7 +81,7 @@ struct RunningSearch ...@@ -81,7 +81,7 @@ struct RunningSearch
{ {
// store search properties // store search properties
int continueOnPage; int continueOnPage;
HighlightRect continueOnMatch; NormalizedRect continueOnMatch;
QValueList< int > highlightedPages; QValueList< int > highlightedPages;
// fields related to previous searches (used for 'continueSearch') // fields related to previous searches (used for 'continueSearch')
...@@ -619,21 +619,19 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar ...@@ -619,21 +619,19 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar
// loop on a page adding highlights for all found items // loop on a page adding highlights for all found items
bool addedHighlights = false; bool addedHighlights = false;
HighlightRect * lastMatch = 0; NormalizedRect * lastMatch = 0;
while ( 1 ) while ( 1 )
{ {
if ( lastMatch ) if ( lastMatch )
lastMatch = page->searchText( text, caseSensitive, lastMatch ); lastMatch = page->findText( text, caseSensitive, lastMatch );
else else
lastMatch = page->searchText( text, caseSensitive ); lastMatch = page->findText( text, caseSensitive );
if ( !lastMatch ) if ( !lastMatch )
break; break;
// add highligh rect to the page // add highligh rect to the page
lastMatch->id = searchID; page->setHighlight( searchID, lastMatch, color );
lastMatch->color = color;
page->setHighlight( lastMatch );
addedHighlights = true; addedHighlights = true;
} }
...@@ -663,45 +661,38 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar ...@@ -663,45 +661,38 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar
KPDFPage * lastPage = fromStart ? 0 : pages_vector[ currentPage ]; KPDFPage * lastPage = fromStart ? 0 : pages_vector[ currentPage ];
// continue checking last SearchPage first (if it is the current page) // continue checking last SearchPage first (if it is the current page)
HighlightRect * r = 0; NormalizedRect * match = 0;
if ( lastPage && lastPage->number() == s->continueOnPage ) if ( lastPage && lastPage->number() == s->continueOnPage )
{ {
if ( newText ) if ( newText )
r = lastPage->searchText( text, caseSensitive ); match = lastPage->findText( text, caseSensitive );
else
r = lastPage->searchText( text, caseSensitive, &s->continueOnMatch );
if ( r )
{
s->continueOnMatch = *r;
s->highlightedPages.append( currentPage );
}
else else
match = lastPage->findText( text, caseSensitive, &s->continueOnMatch );
if ( !match )
currentPage++; currentPage++;
} }
// if no match found, loop through the whole doc, starting from currentPage // if no match found, loop through the whole doc, starting from currentPage
if ( !r ) if ( !match )
{ {
const int pageCount = pages_vector.count(); const int pageCount = pages_vector.count();
for ( int i = 0; i < pageCount; i++ ) for ( int i = 0; i < pageCount; i++ )
{ {
if ( currentPage >= pageCount ) if ( currentPage >= pageCount )
{ {
if ( !noDialogs && KMessageBox::questionYesNo(0, i18n("End of document reached.\nContinue from the beginning?")) == KMessageBox::Yes ) if ( noDialogs || KMessageBox::questionYesNo(0, i18n("End of document reached.\nContinue from the beginning?")) == KMessageBox::Yes )
currentPage = 0; currentPage = 0;
else else
break; break;
} }
// get page
KPDFPage * page = pages_vector[ currentPage ]; KPDFPage * page = pages_vector[ currentPage ];
// request search page if needed
if ( !page->hasSearchPage() ) if ( !page->hasSearchPage() )
requestTextPage( page->number() ); requestTextPage( page->number() );
if ( (r = page->searchText( text, caseSensitive )) ) // if found a match on the current page, end the loop
{ if ( (match = page->findText( text, caseSensitive )) )
s->continueOnPage = currentPage;
s->continueOnMatch = *r;
s->highlightedPages.append( currentPage );
break; break;
}
currentPage++; currentPage++;
} }
} }
...@@ -710,27 +701,27 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar ...@@ -710,27 +701,27 @@ bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStar
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
// if a match has been found.. // if a match has been found..
if ( r ) if ( match )
{ {
// update the RunningSearch structure adding this match..
foundAMatch = true; foundAMatch = true;
s->continueOnPage = currentPage;
s->continueOnMatch = *match;
s->highlightedPages.append( currentPage );
// ..add highlight to the page.. // ..add highlight to the page..
int pageNumber = currentPage; pages_vector[ currentPage ]->setHighlight( searchID, match, color );
KPDFPage * foundPage = pages_vector[ currentPage ];
r->id = searchID;
r->color = color;
foundPage->setHighlight( r );
// ..queue page for notifying changes.. // ..queue page for notifying changes..
if ( !pagesToNotify.contains( pageNumber ) ) if ( !pagesToNotify.contains( currentPage ) )
pagesToNotify.append( pageNumber ); pagesToNotify.append( currentPage );
// ..move the viewport to show the searched word centered // ..move the viewport to show the searched word centered
if ( moveViewport ) if ( moveViewport )
{ {
DocumentViewport searchViewport( pageNumber ); DocumentViewport searchViewport( currentPage );
searchViewport.reCenter.enabled = true; searchViewport.reCenter.enabled = true;
searchViewport.reCenter.normalizedCenterX = (r->left + r->right) / 2.0; searchViewport.reCenter.normalizedCenterX = (match->left + match->right) / 2.0;
searchViewport.reCenter.normalizedCenterY = (r->top + r->bottom) / 2.0; searchViewport.reCenter.normalizedCenterY = (match->top + match->bottom) / 2.0;
setViewport( searchViewport, -1, true ); setViewport( searchViewport, -1, true );
} }
} }
...@@ -831,6 +822,11 @@ void KPDFDocument::processLink( const KPDFLink * link ) ...@@ -831,6 +822,11 @@ void KPDFDocument::processLink( const KPDFLink * link )
kdWarning() << "Link: Error opening '" << go->fileName() << "'." << endl; kdWarning() << "Link: Error opening '" << go->fileName() << "'." << endl;
return; return;
} }
else
{
setViewport( d->nextDocumentViewport );
d->nextDocumentViewport = DocumentViewport();
}
} break; } break;
......
...@@ -164,7 +164,12 @@ void KPDFOutputDev::drawLink( Link * link, Catalog * catalog ) ...@@ -164,7 +164,12 @@ void KPDFOutputDev::drawLink( Link * link, Catalog * catalog )
int left, top, right, bottom; int left, top, right, bottom;
cvtUserToDev( x1, y1, &left, &top ); cvtUserToDev( x1, y1, &left, &top );
cvtUserToDev( x2, y2, &right, &bottom ); cvtUserToDev( x2, y2, &right, &bottom );
KPDFPageRect * rect = new KPDFPageRect( left, top, right, bottom ); double nl = (double)left / (double)m_pixmapWidth,
nt = (double)top / (double)m_pixmapHeight,
nr = (double)right / (double)m_pixmapWidth,
nb = (double)bottom / (double)m_pixmapHeight;
// create the rect using normalized coords
KPDFPageRect * rect = new KPDFPageRect( nl, nt, nr, nb );
// attach the link object to the rect and add it to the vector container // attach the link object to the rect and add it to the vector container
rect->setPointer( l, KPDFPageRect::Link ); rect->setPointer( l, KPDFPageRect::Link );
m_rects.push_back( rect ); m_rects.push_back( rect );
...@@ -220,7 +225,12 @@ void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str, ...@@ -220,7 +225,12 @@ void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str,
if ( width > 10 && height > 10 ) if ( width > 10 && height > 10 )
{ {
// build a descriptor for the image rect // build a descriptor for the image rect
KPDFPageRect * r = new KPDFPageRect( left, top, left + width, top + height ); double nl = (double)left / (double)m_pixmapWidth,
nt = (double)top / (double)m_pixmapHeight,
nr = (double)(left + width) / (double)m_pixmapWidth,
nb = (double)(top + height) / (double)m_pixmapHeight;
// create the rect using normalized coords
KPDFPageRect * r = new KPDFPageRect( nl, nt, nr, nb );
r->setPointer( 0, KPDFPageRect::Image ); r->setPointer( 0, KPDFPageRect::Image );
// add the rect to the vector container // add the rect to the vector container
m_rects.push_back( r ); m_rects.push_back( r );
......
...@@ -49,22 +49,6 @@ KPDFPage::~KPDFPage() ...@@ -49,22 +49,6 @@ KPDFPage::~KPDFPage()
} }
bool KPDFPage::hasHighlights( int id ) const
{
// simple case: have no highlights
if ( m_highlights.isEmpty() )
return false;
// simple case: we have highlights and no id to match
if ( id == -1 )
return true;
// iterate on the highlights list to find an entry by id
QValueList< HighlightRect * >::const_iterator it = m_highlights.begin(), end = m_highlights.end();
for ( ; it != end; ++it )
if ( (*it)->id == id )
return true;
return false;
}
bool KPDFPage::hasPixmap( int id, int width, int height ) const bool KPDFPage::hasPixmap( int id, int width, int height ) const
{ {
if ( !m_pixmaps.contains( id ) ) if ( !m_pixmaps.contains( id ) )
...@@ -80,54 +64,45 @@ bool KPDFPage::hasSearchPage() const ...@@ -80,54 +64,45 @@ bool KPDFPage::hasSearchPage() const
return m_text != 0; return m_text != 0;
} }
bool KPDFPage::hasRect( int mouseX, int mouseY ) const bool KPDFPage::hasBookmark() const
{
return m_bookmarked;
}
bool KPDFPage::hasRect( double x, double y ) const
{ {
if ( m_rects.count() < 1 ) if ( m_rects.count() < 1 )
return false; return false;
QValueList< KPDFPageRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); QValueList< KPDFPageRect * >::const_iterator it = m_rects.begin(), end = m_rects.end();
for ( ; it != end; ++it ) for ( ; it != end; ++it )
if ( (*it)->contains( mouseX, mouseY ) ) if ( (*it)->contains( x, y ) )
return true; return true;
return false; return false;
} }
bool KPDFPage::hasLink( int mouseX, int mouseY ) const bool KPDFPage::hasHighlights( int s_id ) const
{
const KPDFPageRect *r;
r = getRect( mouseX, mouseY);
return r && r->pointerType() == KPDFPageRect::Link;
}
const KPDFPageRect * KPDFPage::getRect( int mouseX, int mouseY ) const
{ {
QValueList< KPDFPageRect * >::const_iterator it = m_rects.begin(), end = m_rects.end(); // simple case: have no highlights
if ( m_highlights.isEmpty() )
return false;
// simple case: we have highlights and no id to match
if ( s_id == -1 )
return true;
// iterate on the highlights list to find an entry by id
QValueList< HighlightRect * >::const_iterator it = m_highlights.begin(), end = m_highlights.end();
for ( ; it != end; ++it ) for ( ; it != end; ++it )
if ( (*it)->contains( mouseX, mouseY ) ) if ( (*it)->s_id == s_id )
return *it; return true;
return 0; return false;
} }
const KPDFPageTransition * KPDFPage::getTransition() const bool KPDFPage::hasTransition() const
{ {
return m_transition; return m_transition != 0;
}
const QString KPDFPage::getTextInRect( const QRect & rect, double zoom ) const
{
if ( !m_text )
return QString::null;
int left = (int)((double)rect.left() / zoom),
top = (int)((double)rect.top() / zoom),
right = (int)((double)rect.right() / zoom),
bottom = (int)((double)rect.bottom() / zoom);
GString * text = m_text->getText( left, top, right, bottom );
QString result = QString::fromUtf8( text->getCString() );
delete text;
return result;
} }
HighlightRect * KPDFPage::searchText( const QString & text, bool strictCase, HighlightRect * lastRect ) NormalizedRect * KPDFPage::findText( const QString & text, bool strictCase, NormalizedRect * lastRect ) const
{ {
if ( text.isEmpty() ) if ( text.isEmpty() )
return 0; return 0;
...@@ -178,12 +153,41 @@ HighlightRect * KPDFPage::searchText( const QString & text, bool strictCase, Hig ...@@ -178,12 +153,41 @@ HighlightRect * KPDFPage::searchText( const QString & text, bool strictCase, Hig
} }
} }
// if the page was found, return a new normalized HighlightRect // if the page was found, return a new normalizedRect
if ( found ) if ( found )
return new HighlightRect( sLeft / m_width, sTop / m_height, sRight / m_width, sBottom / m_height ); return new NormalizedRect( sLeft / m_width, sTop / m_height, sRight / m_width, sBottom / m_height );
return 0;
}
const QString KPDFPage::getText( const NormalizedRect & rect ) const
{
if ( !m_text )
return QString::null;
int left = (int)( rect.left * m_width ),
top = (int)( rect.top * m_height ),
right = (int)( rect.right * m_width ),
bottom = (int)( rect.bottom * m_height );
GString * text = m_text->getText( left, top, right, bottom );
QString result = QString::fromUtf8( text->getCString() );
delete text;
return result;
}
const KPDFPageRect * KPDFPage::getRect( double x, double y ) const
{
QValueList< KPDFPageRect * >::const_iterator it = m_rects.begin(), end = m_rects.end();
for ( ; it != end; ++it )
if ( (*it)->contains( x, y ) )
return *it;
return 0; return 0;
} }
const KPDFPageTransition * KPDFPage::getTransition() const
{
return m_transition;
}
void KPDFPage::setPixmap( int id, QPixmap * pixmap ) void KPDFPage::setPixmap( int id, QPixmap * pixmap )
{ {
if ( m_pixmaps.contains( id ) ) if ( m_pixmaps.contains( id ) )
...@@ -197,6 +201,11 @@ void KPDFPage::setSearchPage( TextPage * tp ) ...@@ -197,6 +201,11 @@ void KPDFPage::setSearchPage( TextPage * tp )
m_text = tp; m_text = tp;
} }
void KPDFPage::setBookmark( bool state )
{
m_bookmarked = state;
}
void KPDFPage::setRects( const QValueList< KPDFPageRect * > rects ) void KPDFPage::setRects( const QValueList< KPDFPageRect * > rects )
{ {
QValueList< KPDFPageRect * >::iterator it = m_rects.begin(), end = m_rects.end(); QValueList< KPDFPageRect * >::iterator it = m_rects.begin(), end = m_rects.end();
...@@ -205,11 +214,21 @@ void KPDFPage::setRects( const QValueList< KPDFPageRect * > rects ) ...@@ -205,11 +214,21 @@ void KPDFPage::setRects( const QValueList< KPDFPageRect * > rects )
m_rects = rects; m_rects = rects;
} }
void KPDFPage::setHighlight( HighlightRect * hr, bool add ) void KPDFPage::setHighlight( int s_id, NormalizedRect * &rect, const QColor & color )
{ {
if ( !add ) // create a HighlightRect descriptor taking values from params
deleteHighlights( hr->id ); HighlightRect * hr = new HighlightRect();
hr->s_id = s_id;
hr->color = color;
hr->left = rect->left;
hr->top = rect->top;
hr->right = rect->right;
hr->bottom = rect->bottom;
// append the HighlightRect to the list
m_highlights.append( hr ); m_highlights.append( hr );
// delete old object and change reference
delete rect;
rect = hr;
} }
void KPDFPage::setTransition( const KPDFPageTransition * transition ) void KPDFPage::setTransition( const KPDFPageTransition * transition )
...@@ -241,14 +260,14 @@ void KPDFPage::deletePixmapsAndRects() ...@@ -241,14 +260,14 @@ void KPDFPage::deletePixmapsAndRects()
m_rects.clear(); m_rects.clear();
} }
void KPDFPage::deleteHighlights( int id ) void KPDFPage::deleteHighlights( int s_id )
{ {
// delete highlights by ID // delete highlights by ID
QValueList< HighlightRect * >::iterator it = m_highlights.begin(), end = m_highlights.end(); QValueList< HighlightRect * >::iterator it = m_highlights.begin(), end = m_highlights.end();
while ( it != end ) while ( it != end )
{ {
HighlightRect * highlight = *it; HighlightRect * highlight = *it;
if ( id == -1 || highlight->id == id ) if ( s_id == -1 || highlight->s_id == s_id )
{ {
it = m_highlights.remove( it ); it = m_highlights.remove( it );
delete highlight; delete highlight;
...@@ -259,31 +278,56 @@ void KPDFPage::deleteHighlights( int id ) ...@@ -259,31 +278,56 @@ void KPDFPage::deleteHighlights( int id )
} }
/** class KPDFPageRect **/ /** class NormalizedRect **/
NormalizedRect::NormalizedRect()
: left( 0.0 ), top( 0.0 ), right( 0.0 ), bottom( 0.0 ) {}
NormalizedRect::NormalizedRect( double l, double t, double r, double b )
// note: check for swapping coords?
: left( l ), top( t ), right( r ), bottom( b ) {}
NormalizedRect::NormalizedRect( const QRect & r, double xScale, double yScale )
: left( (double)r.left() / xScale ), top( (double)r.top() / yScale ),
right( (double)r.right() / xScale ), bottom( (double)r.bottom() / yScale ) {}
KPDFPageRect::KPDFPageRect( int l, int t, int r, int b ) bool NormalizedRect::contains( double x, double y ) const
: m_pointerType( NoPointer ), m_pointer( 0 )
{ {
// assign coordinates swapping them if negative width or height return x >= left && x <= right && y >= top && y <= bottom;
m_xMin = r > l ? l : r;
m_xMax = r > l ? r : l;
m_yMin = b > t ? t : b;
m_yMax = b > t ? b : t;
} }
KPDFPageRect::~KPDFPageRect() bool NormalizedRect::intersects( const NormalizedRect & r ) const
{ {
deletePointer(); return (r.left < right) && (r.right > left) && (r.top < bottom) && (r.bottom > top);
}
bool NormalizedRect::intersects( double l, double t, double r, double b ) const
{
return (l < right) && (r > left) && (t < bottom) && (b > top);
} }
bool KPDFPageRect::contains( int x, int y ) const
/** class KPDFPageRect **/
KPDFPageRect::KPDFPageRect( double l, double t, double r, double b )
// assign coordinates swapping them if negative width or height
: NormalizedRect( r > l ? l : r, b > t ? t : b, r > l ? r : l, b > t ? b : t ),
m_pointerType( NoPointer ), m_pointer( 0 )
{ {
return (x > m_xMin) && (x < m_xMax) && (y > m_yMin) && (y < m_yMax);
} }
QRect KPDFPageRect::geometry() const KPDFPageRect::~KPDFPageRect()
{ {
return QRect( m_xMin, m_yMin, m_xMax - m_xMin, m_yMax - m_yMin ); deletePointer();
}
QRect KPDFPageRect::geometry( int width, int height ) const
{
int l = (int)( left * width ),
t = (int)( top * height ),
r = (int)( right * width ),
b = (int)( bottom * height );
return QRect( l, t, r - l, b - t );
} }
void KPDFPageRect::setPointer( void * object, enum PointerType pType ) void KPDFPageRect::setPointer( void * object, enum PointerType pType )
...@@ -314,16 +358,3 @@ void KPDFPageRect::deletePointer() ...@@ -314,16 +358,3 @@ void KPDFPageRect::deletePointer()
kdDebug() << "Object deletion not implemented for type '" kdDebug() << "Object deletion not implemented for type '"
<< m_pointerType << "' ." << endl; << m_pointerType << "' ." << endl;
} }
/** class HighlightRect **/
HighlightRect::HighlightRect()
: id( -1 ), left( 0.0 ), top( 0.0 ), right( 0.0 ), bottom( 0.0 )
{
}
HighlightRect::HighlightRect( double l, double t, double r, double b )
: id( -1 ), left( l ), top( t ), right( r ), bottom( b )
{
}
...@@ -18,6 +18,7 @@ class QRect; ...@@ -18,6 +18,7 @@ class QRect;
class TextPage; class TextPage;
class KPDFPageRect; class KPDFPageRect;
class KPDFPageTransition; class KPDFPageTransition;
class NormalizedRect;
class HighlightRect; class HighlightRect;
/** /**
...@@ -27,7 +28,10 @@ class HighlightRect; ...@@ -27,7 +28,10 @@ class HighlightRect;
* a search page (a class used internally for retrieving text), rect classes * a search page (a class used internally for retrieving text), rect classes
* (that describe links or other active areas in the current page) and more. * (that describe links or other active areas in the current page) and more.
* *
* Note: All objects are reparented to this class. * All coordinates are normalized to the page, so {x,y} are valid in [0,1]
* range as long as NormalizedRect components.
*
* Note: The class takes ownership of all objects.
*/ */
class KPDFPage class KPDFPage
{ {
...@@ -35,38 +39,34 @@ class KPDFPage ...@@ -35,38 +39,34 @@ class KPDFPage
KPDFPage( uint number, float width, float height, int rotation ); KPDFPage( uint number, float width, float height, int rotation );
~KPDFPage(); ~KPDFPage();
enum KPDFPageAttributes { Bookmark = 1, Highlights = 2 };
// query properties (const read-only methods)