Abstracted Generator and ported xpdf dependant code (most of) to the

GeneratorPDF class. Adapted the whole KPDFLink class to a hieracy of
classes and added a Viewport description associated to 'Goto' links.

Link hasn't got geometry properties. A PageRect class has born to describe
all 'active rects' on a page (hand pointed on mouse over). PageRect can
contain many type of objects such as Links or other active items (images,
...). The Page class now stores PageRects only (no more geometric Links,
as already said).

Added a DocumentInfo class filled in by generators and used by the
PropertiesDialog.

Outline hasn't been abstracted while now, but a DocumentSynopsis class
is in place and work needs to be done to make GeneratorPDF fill in a
DocumentSynopsis instance and pass it to the Toc widget.

Note1: Document has nothing more to do with xpdf, it only commands its
generator.
Note2: 2 remaining classes to be abstracted: Outline, TextPage. But
waning..

svn path=/branches/kpdf_experiments/kdegraphics/kpdf/; revision=369651
This commit is contained in:
Enrico Ros 2004-12-10 16:04:45 +00:00
parent 18e7d798c8
commit 5f4236d801
21 changed files with 1439 additions and 1181 deletions

View file

@ -42,7 +42,7 @@ shellrc_DATA = kpdf_shell.rc
kde_module_LTLIBRARIES = libkpdfpart.la
# the Part's source, library search path, and link libraries
libkpdfpart_la_SOURCES = QOutputDev.cpp kpdf_part.cpp pageview.cpp thumbnaillist.cpp kpdf_error.cpp thumbnailgenerator.cpp document.cpp page.cpp searchwidget.cpp toc.cpp kpdf_dcop.skel pageviewutils.cpp properties.ui propertiesdialog.cpp
libkpdfpart_la_SOURCES = pageview.cpp pageviewutils.cpp thumbnaillist.cpp toc.cpp searchwidget.cpp document.cpp page.cpp link.cpp properties.ui propertiesdialog.cpp QOutputDev.cpp generator_pdf.cpp kpdf_dcop.skel kpdf_error.cpp kpdf_part.cpp
libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
libkpdfpart_la_LIBADD = ../xpdf/libxpdf.la conf/libconf.la $(LIB_KPARTS) $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm

View file

@ -23,17 +23,21 @@
#include <qpixmap.h>
#include <qimage.h>
#include "page.h"
#include "GfxState.h"
#include "SplashBitmap.h"
#include "TextOutputDev.h"
#include "QOutputDev.h"
#include "generator_pdf.h"
#include "page.h"
#include "link.h"
#include "xpdf/Link.h"
#include "xpdf/GfxState.h"
#include "xpdf/TextOutputDev.h"
#include "splash/SplashBitmap.h"
// NOTE: XPDF/Splash implementation dependant code will be marked with '###'
//NOTE: XPDF/Splash *implementation dependant* code is marked with '###'
// BEGIN KPDFOutputDev
//BEGIN KPDFOutputDev
KPDFOutputDev::KPDFOutputDev( SplashColor paperColor )
: SplashOutputDev( splashModeRGB8, false, paperColor ), m_pixmap( 0 ), m_text( 0 )
: SplashOutputDev( splashModeRGB8, false, paperColor ), m_pixmap( 0 ),
m_generator( 0 ), m_text( 0 )
{
}
@ -42,7 +46,7 @@ KPDFOutputDev::~KPDFOutputDev()
clear();
}
void KPDFOutputDev::setParams( int width, int height, bool genT, bool genL, bool genAR )
void KPDFOutputDev::setParams( int width, int height, bool genT, bool genL, bool genI, GeneratorPDF * parent )
{
clear();
@ -51,12 +55,94 @@ void KPDFOutputDev::setParams( int width, int height, bool genT, bool genL, bool
m_generateText = genT;
m_generateLinks = genL;
m_generateActiveRects = genAR;
m_generateImages = genI;
m_generator = parent;
if ( m_generateText )
m_text = new TextPage( gFalse );
}
KPDFLink * KPDFOutputDev::generateLink( LinkAction * a )
{
KPDFLink * link = 0;
switch ( a->getKind() )
{
case actionGoTo:
{
LinkGoTo * g = (LinkGoTo *) a;
// ceate link: no ext file, namedDest, object pointer
link = new KPDFLinkGoto( QString::null, m_generator->decodeLinkViewport( g->getNamedDest(), g->getDest() ) );
}
break;
case actionGoToR:
{
LinkGoToR * g = (LinkGoToR *) a;
// copy link file
const char * fileName = g->getFileName()->getCString();
// ceate link: fileName, namedDest, object pointer
link = new KPDFLinkGoto( (QString)fileName, m_generator->decodeLinkViewport( g->getNamedDest(), g->getDest() ) );
}
break;
case actionLaunch:
{
LinkLaunch * e = (LinkLaunch *)a;
GString * p = e->getParams();
link = new KPDFLinkExecute( e->getFileName()->getCString(), p ? p->getCString() : 0 );
}
break;
case actionNamed:
{
const char * name = ((LinkNamed *)a)->getName()->getCString();
if ( !strcmp( name, "NextPage" ) )
link = new KPDFLinkAction( KPDFLinkAction::PageNext );
else if ( !strcmp( name, "PrevPage" ) )
link = new KPDFLinkAction( KPDFLinkAction::PagePrev );
else if ( !strcmp( name, "FirstPage" ) )
link = new KPDFLinkAction( KPDFLinkAction::PageFirst );
else if ( !strcmp( name, "LastPage" ) )
link = new KPDFLinkAction( KPDFLinkAction::PageLast );
else if ( !strcmp( name, "GoBack" ) )
link = new KPDFLinkAction( KPDFLinkAction::HistoryBack );
else if ( !strcmp( name, "GoForward" ) )
link = new KPDFLinkAction( KPDFLinkAction::HistoryForward );
else if ( !strcmp( name, "Quit" ) )
link = new KPDFLinkAction( KPDFLinkAction::Quit );
else
kdDebug() << "Unknown named action: '" << name << "'" << endl;
}
break;
case actionURI:
link = new KPDFLinkBrowse( ((LinkURI *)a)->getURI()->getCString() );
break;
case actionMovie:
/* { TODO this
m_type = Movie;
LinkMovie * m = (LinkMovie *) a;
// copy Movie parameters (2 IDs and a const char *)
Ref * r = m->getAnnotRef();
m_refNum = r->num;
m_refGen = r->gen;
copyString( m_uri, m->getTitle()->getCString() );
}
*/ break;
case actionUnknown:
kdDebug() << "Unknown link." << endl;
break;
}
// link may be zero at that point
return link;
}
QPixmap * KPDFOutputDev::takePixmap()
{
QPixmap * pix = m_pixmap;
@ -71,16 +157,9 @@ TextPage * KPDFOutputDev::takeTextPage()
return text;
}
QValueList< KPDFLink * > KPDFOutputDev::takeLinks()
QValueList< KPDFPageRect * > KPDFOutputDev::takeRects()
{
QValueList< KPDFLink * > linksCopy( m_links );
m_links.clear();
return linksCopy;
}
QValueList< KPDFActiveRect * > KPDFOutputDev::takeActiveRects()
{
QValueList< KPDFActiveRect * > rectsCopy( m_rects );
QValueList< KPDFPageRect * > rectsCopy( m_rects );
m_rects.clear();
return rectsCopy;
}
@ -122,17 +201,21 @@ void KPDFOutputDev::drawLink( Link * link, Catalog * catalog )
if ( m_generateLinks )
{
// create the new KPDFLink ...
KPDFLink * l = new KPDFLink( link->getAction() );
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 );
// ... and assign its coords withing current page geometry
l->setGeometry( left, top, right, bottom );
// add the link to the vector container
m_links.push_back( l );
// create the link descriptor
KPDFLink * l = generateLink( link->getAction() );
if ( l )
{
// create the page rect representing the link
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 );
KPDFPageRect * rect = new KPDFPageRect( left, top, right, bottom );
// attach the link object to the rect and add it to the vector container
rect->setPointer( l, KPDFPageRect::Link );
m_rects.push_back( rect );
}
}
SplashOutputDev::drawLink( link, catalog );
}
@ -161,7 +244,7 @@ GBool KPDFOutputDev::beginType3Char( GfxState *state, double x, double y, double
void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str,
int _width, int _height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg )
{
if ( m_generateActiveRects )
if ( m_generateImages )
{
// find out image rect from the Coord Transform Matrix
double * ctm = state->getCTM();
@ -183,7 +266,9 @@ void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str,
}
if ( width > 10 && height > 10 )
{
KPDFActiveRect * r = new KPDFActiveRect( left, top, width, height );
// build a descriptor for the image rect
KPDFPageRect * r = new KPDFPageRect( left, top, left + width, top + height );
r->setPointer( 0, KPDFPageRect::Image );
// add the rect to the vector container
m_rects.push_back( r );
}
@ -193,18 +278,10 @@ void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str,
void KPDFOutputDev::clear()
{
// delete links
if ( m_links.count() )
{
QValueList< KPDFLink * >::iterator it = m_links.begin(), end = m_links.end();
for ( ; it != end; ++it )
delete *it;
m_links.clear();
}
// delete activerects
// delete rects
if ( m_rects.count() )
{
QValueList< KPDFActiveRect * >::iterator it = m_rects.begin(), end = m_rects.end();
QValueList< KPDFPageRect * >::iterator it = m_rects.begin(), end = m_rects.end();
for ( ; it != end; ++it )
delete *it;
m_rects.clear();
@ -222,10 +299,10 @@ void KPDFOutputDev::clear()
m_text = 0;
}
}
// END KPDFOutputDev
//END KPDFOutputDev
// BEGIN KPDFTextDev
//BEGIN KPDFTextDev
KPDFTextDev::KPDFTextDev()
{
m_text = new TextPage( gFalse );
@ -265,4 +342,4 @@ void KPDFTextDev::drawChar( GfxState *state, double x, double y, double dx, doub
{
m_text->addChar( state, x, y, dx, dy, code, u, uLen );
}
// END KPDFTextDev
//END KPDFTextDev

View file

@ -19,21 +19,25 @@
#pragma interface
#endif
#include "SplashOutputDev.h"
#include "Link.h"
#include <qvaluelist.h>
#include "xpdf/PDFDoc.h" // for 'Object'
#include "xpdf/SplashOutputDev.h"
class QPixmap;
class TextPage;
class GeneratorPDF;
class KPDFLink;
class KPDFActiveRect;
class KPDFPageRect;
/**
* @short A SplashOutputDev renderer that grabs text and links.
* ### MERGE: rename definition/impl to generator_pdf_outputdev.h/.cpp
*
* This output device:
* - renders the page using SplashOutputDev (its parent)
* - harvests text into a textPage (for searching text)
* - harvests links and collect them
* - collects images and collect them as generic 'activerects'
* - harvests links and collects them
* - collects images and collects them
*/
class KPDFOutputDev : public SplashOutputDev
{
@ -43,13 +47,15 @@ class KPDFOutputDev : public SplashOutputDev
// to be called before PDFDoc->displayPage( thisclass, .. )
void setParams( int pixmapWidth, int pixmapHeight, bool generateTextpage,
bool generateLinks, bool generateActiveRects );
bool decodeLinks, bool decodeImages, GeneratorPDF * parent );
// generate a valid KPDFLink subclass (or null) from a xpdf's LinkAction
KPDFLink * generateLink( LinkAction * );
// takes pointers out of the class (so deletion it's up to others)
QPixmap * takePixmap();
TextPage * takeTextPage();
QValueList< KPDFLink * > takeLinks();
QValueList< KPDFActiveRect * > takeActiveRects();
QValueList< KPDFPageRect * > takeRects();
/** inherited from OutputDev */
// Start a page.
@ -74,19 +80,17 @@ class KPDFOutputDev : public SplashOutputDev
// generator switches and parameters
bool m_generateText;
bool m_generateLinks;
bool m_generateActiveRects;
bool m_generateImages;
int m_pixmapWidth;
int m_pixmapHeight;
QPixmap * m_pixmap;
GeneratorPDF * m_generator;
// text page generated on demand
TextPage * m_text;
// links generated on demand
QValueList< KPDFLink * > m_links;
// active areas on page
QValueList< KPDFActiveRect * > m_rects;
// rectangles on page (associated to links/images)
QValueList< KPDFPageRect * > m_rects;
};

View file

@ -7,7 +7,8 @@ Legend:
(*) - Some parts of this item are already done
In progress on the branch (first item comes first):
-> ADD: viewport changes the right way when clicking links (also suggested by Mikolaj Machowski) [40% done]
-> Abstract contents generation [60% missing TextPage, Outline]
-> ADD: viewport changes the right way when clicking links (also suggested by Mikolaj Machowski) [60% done]
-> memory manager with different profiles (mem/cpu tradeoff: {memory saving, normal, memory aggressive}) [0%]
-> async document generator using Albert's generator thread [0%]
@ -53,6 +54,7 @@ More items (first items will enter 'In progress list' first):
-> incremental zoom with fast-refresh (tested but flickering!) or contour tracing
Done (newest feature comes firts):
-> ADD: Use 'Generators' as providers for contents generation.
-> ADD: Add properties dialog (Albert)
-> ADD: Support for show/hide menubar in rmb menu, different from HEAD so that supports Konqueror too (Albert)
-> ADD: Watch File option (Albert)

File diff suppressed because it is too large Load diff

View file

@ -12,11 +12,14 @@
#define _KPDF_DOCUMENT_H_
#include <qvaluevector.h>
#include <qstring.h>
class KPrinter;
class Outline;
class KPDFPage;
class KPDFLink;
class Generator;
class DocumentInfo;
class Outline; // FIXME: ABSTRACT-REDO
/**
* @short Base class for objects being notified when something changes.
@ -45,10 +48,9 @@ class KPDFDocumentObserver
#define TOC_ID 4
/**
* @short The information container. Actions (like open,find) take place here.
* @short The Document. Actions (like open,find) take place here.
*
* xxxxxx
* yyy.
* ### MERGE: comment
*/
class KPDFDocument
{
@ -65,22 +67,12 @@ class KPDFDocument
void reparseConfig();
// query methods (const ones)
const DocumentInfo & documentInfo() const;
const KPDFPage * page( uint page ) const;
uint currentPage() const;
uint pages() const;
QString author() const;
QString creationDate() const;
QString creator() const;
bool encrypted() const;
QString keywords() const;
QString modificationDate() const;
bool optimized() const;
float PDFversion() const;
QString producer() const;
QString subject() const;
QString title() const;
bool okToPrint() const;
Outline * outline() const;
const KPDFPage * page( uint page ) const;
// perform actions on document / pages
void requestPixmap( int id, uint page, int width, int height, bool syncronous = false );
@ -98,7 +90,40 @@ class KPDFDocument
void processPageList( bool documentChanged );
void unHilightPages();
Generator * generator;
QString documentFileName;
QValueVector< KPDFPage * > pages_vector;
class KPDFDocumentPrivate * d;
};
/**
* ### MERGE: comment
*/
struct DocumentInfo
{
QString author,
creationDate,
modificationDate,
creator,
keywords,
producer,
subject,
title,
format,
formatVersion,
encryption,
optimization;
};
/**
* ### TEMP IMPLEMENTATION. ABSTRACT OutLine !!
* ### NOTE: this IMPL is for PDF only. Need to better abstract this.
*/
class DocumentSynopsis
{
public:
Outline * outline;
};
#endif

55
kpdf/generator.h Normal file
View file

@ -0,0 +1,55 @@
/***************************************************************************
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#ifndef _KPDF_GENERATOR_H_
#define _KPDF_GENERATOR_H_
#include <qvaluevector.h>
#include <qstring.h>
class KPrinter;
class KPDFPage;
class KPDFLink;
class KPDFDocument;
class DocumentSynopsis;
class DocumentInfo;
/**
* @short [Abstract Class] The information generator.
*
* Most of class members are pure virtuals and they must be implemented to
* provide a class that builds contents (graphics and text).
*
* Generation/query is requested by the 'KPDFDocument' class only, and that
* class stores the resulting data into 'KPDFPage's. The data will then be
* displayed by the GUI components (pageView, thumbnailList, etc..).
*/
class Generator
{
public:
// load a document and fill up the pagesVector
virtual bool loadDocument( const QString & fileName, QValueVector< KPDFPage* > & pagesVector ) = 0;
// Document description
virtual const DocumentInfo & documentInfo() = 0;
// DRM handling
enum Permissions { Modify = 1, Copy = 2, Print = 4, AddNotes = 8 };
virtual bool allowed( int /*permisisons*/ ) { return true; }
// perform actions (/request content generation)
virtual bool print( KPrinter& printer ) = 0;
virtual bool requestPixmap( int id, KPDFPage * page, int width, int height, bool syncronous = false ) = 0;
virtual void requestTextPage( KPDFPage * page ) = 0;
virtual DocumentSynopsis& synopsis() = 0;
// check configuration and return if something changed
virtual bool reparseConfig() { return false; }
};
#endif

548
kpdf/generator_pdf.cpp Normal file
View file

@ -0,0 +1,548 @@
/***************************************************************************
* Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
// qt/kde includes
#include <qfile.h>
#include <klocale.h>
#include <kpassdlg.h>
#include <kprinter.h>
#include <ktempfile.h>
#include <kmessagebox.h>
#include <kdebug.h>
// xpdf includes
#include "xpdf/PSOutputDev.h"
#include "xpdf/Link.h"
#include "xpdf/ErrorCodes.h"
#include "xpdf/UnicodeMap.h"
// local includes
#include "generator_pdf.h"
#include "document.h" //for PAGEVIEW_ID
#include "page.h"
#include "settings.h"
#include "QOutputDev.h"
GeneratorPDF::GeneratorPDF()
: pdfdoc( 0 ), kpdfOutputDev( 0 ), docInfoDirty( true )
{
// generate kpdfOutputDev and cache page color
reparseConfig();
syn.outline = 0;
}
GeneratorPDF::~GeneratorPDF()
{
docLock.lock();
delete kpdfOutputDev;
delete pdfdoc;
docLock.unlock();
}
bool GeneratorPDF::loadDocument( const QString & fileName, QValueVector<KPDFPage*> & pagesVector )
{
// create PDFDoc for the given file
GString *filename = new GString( QFile::encodeName( fileName ) );
delete pdfdoc;
pdfdoc = new PDFDoc( filename, 0, 0 );
// if the file didn't open correctly it might be encrypted, so ask for a pass
if ( !pdfdoc->isOk() )
{
if ( pdfdoc->getErrorCode() == errEncrypted )
{
bool first, correct;
QString prompt;
QCString pwd;
first = true;
correct = false;
while( !correct )
{
if ( first )
{
prompt = i18n( "Please insert the password to read the document:" );
first = false;
}
else prompt = i18n( "Incorrect password. Try again:" );
if ( KPasswordDialog::getPassword( pwd, prompt ) == KPasswordDialog::Accepted )
{
GString *pwd2;
pwd2 = new GString( pwd.data() );
pdfdoc = new PDFDoc( filename, pwd2, pwd2 );
delete pwd2;
correct = pdfdoc->isOk();
if ( !correct && pdfdoc->getErrorCode() != errEncrypted )
{
delete pdfdoc;
pdfdoc = 0;
return false;
}
}
else
{
delete pdfdoc;
pdfdoc = 0;
return false;
}
}
}
else
{
delete pdfdoc;
pdfdoc = 0;
return false;
}
}
// initialize output device for rendering current pdf
kpdfOutputDev->startDoc( pdfdoc->getXRef() );
// build Pages (currentPage was set -1 by deletePages)
uint pageCount = pdfdoc->getNumPages();
pagesVector.resize( pageCount );
for ( uint i = 0; i < pageCount ; i++ )
pagesVector[i] = new KPDFPage( i, pdfdoc->getPageWidth(i+1), pdfdoc->getPageHeight(i+1), pdfdoc->getPageRotate(i+1) );
// the file has been loaded correctly
return true;
}
const DocumentInfo & GeneratorPDF::documentInfo()
{
if ( docInfoDirty )
{
// compile internal structure reading properties from PDFDoc
docInfo.author = getDocumentInfo("Author");
docInfo.creationDate = getDocumentDate("CreationDate");
docInfo.modificationDate = getDocumentDate("ModDate");
docInfo.creator = getDocumentInfo("Creator");
docInfo.keywords = getDocumentInfo("Keywords");
docInfo.producer = getDocumentInfo("Producer");
docInfo.subject = getDocumentInfo("Subject");
docInfo.title = getDocumentInfo("Title");
docInfo.format = "PDF";
if ( pdfdoc )
{
docInfo.formatVersion = QString::number( pdfdoc->getPDFVersion() );
docInfo.encryption = pdfdoc->isEncrypted() ? i18n( "Encrypted" ) : i18n( "Unencrypted" );
docInfo.optimization = pdfdoc->isLinearized() ? i18n( "Yes" ) : i18n( "No" );
}
else
{
docInfo.formatVersion = i18n( "Unknown Version" );
docInfo.encryption = i18n( "Unknown Encryption" );
docInfo.optimization = i18n( "Unknown Optimization" );
}
// if pdfdoc is valid then we cached good info -> don't cache them again
if ( pdfdoc )
docInfoDirty = false;
}
return docInfo;
}
bool GeneratorPDF::print( KPrinter& printer )
{
KTempFile tf( QString::null, ".ps" );
PSOutputDev *psOut = new PSOutputDev(tf.name().latin1(), pdfdoc->getXRef(), pdfdoc->getCatalog(), 1, pdfdoc->getNumPages(), psModePS);
if (psOut->isOk())
{
std::list<int> pages;
if (!printer.previewOnly())
{
QValueList<int> pageList = printer.pageList();
QValueList<int>::const_iterator it;
for(it = pageList.begin(); it != pageList.end(); ++it) pages.push_back(*it);
}
else
{
for(int i = 1; i <= pdfdoc->getNumPages(); i++) pages.push_back(i);
}
docLock.lock();
pdfdoc->displayPages(psOut, pages, 72, 72, 0, globalParams->getPSCrop(), gFalse);
docLock.unlock();
// needs to be here so that the file is flushed, do not merge with the one
// in the else
delete psOut;
printer.printFiles(tf.name(), true);
return true;
}
else
{
delete psOut;
return false;
}
}
bool GeneratorPDF::requestPixmap( int id, KPDFPage * page, int width, int height, bool syncronous )
{
//kdDebug() << "id: " << id << " is requesting pixmap for page " << page->number() << " [" << width << " x " << height << "]." << endl;
if ( syncronous )
{
// in-place Pixmap generation for syncronous requests
if ( !page->hasPixmap( id, width, height ) )
{
// compute dpi used to get an image with desired width and height
double fakeDpiX = width * 72.0 / page->width(),
fakeDpiY = height * 72.0 / page->height();
// 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?
bool genTextPage = !page->hasSearchPage() && (width == page->width()) && (height == page->height());
// generate links and image rects if rendering pages on pageview
bool genRects = id == PAGEVIEW_ID;
kpdfOutputDev->setParams( width, height, genTextPage, genRects, genRects, this );
docLock.lock();
pdfdoc->displayPage( kpdfOutputDev, page->number() + 1, fakeDpiX, fakeDpiY, 0, true, genRects );
docLock.unlock();
page->setPixmap( id, kpdfOutputDev->takePixmap() );
if ( genTextPage )
page->setSearchPage( kpdfOutputDev->takeTextPage() );
if ( genRects )
page->setRects( kpdfOutputDev->takeRects() );
// pixmap generated
return true;
}
}
else
{
//TODO asyncronous events queuing
return false;
}
// no pixmap generated
return false;
}
void GeneratorPDF::requestTextPage( KPDFPage * page )
{
// build a TextPage using the lightweight KPDFTextDev generator..
KPDFTextDev td;
docLock.lock();
pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, true, false );
docLock.unlock();
// ..and attach it to the page
page->setSearchPage( td.takeTextPage() );
}
DocumentSynopsis& GeneratorPDF::synopsis()
{
syn.outline = pdfdoc->getOutline();
return syn;
}
bool GeneratorPDF::reparseConfig()
{
// load paper color from Settings or use the white default color
QColor color = ( (Settings::renderMode() == Settings::EnumRenderMode::Paper ) &&
Settings::changeColors() ) ? Settings::paperColor() : Qt::white;
// if paper color is changed we have to rebuild every visible pixmap in addition
// to the outputDevice. it's the 'heaviest' case, other effect are just recoloring
// over the page rendered on 'standard' white background.
if ( color != paperColor || !kpdfOutputDev )
{
paperColor = color;
SplashColor splashCol;
splashCol.rgb8 = splashMakeRGB8( paperColor.red(), paperColor.green(), paperColor.blue() );
// rebuild the output device using the new paper color
docLock.lock();
delete kpdfOutputDev;
kpdfOutputDev = new KPDFOutputDev( splashCol );
if ( pdfdoc )
kpdfOutputDev->startDoc( pdfdoc->getXRef() );
docLock.unlock();
return true;
}
return false;
}
KPDFLinkGoto::Viewport GeneratorPDF::decodeLinkViewport( GString * namedDest, LinkDest * dest )
// note: this function is called when processing a page, when the MUTEX is already LOCKED
{
KPDFLinkGoto::Viewport vp;
vp.page = -1;
if ( namedDest && !dest )
dest = pdfdoc->findDest( namedDest );
if ( !dest || !dest->isOk() )
return vp;
// get destination page number
if ( !dest->isPageRef() )
vp.page = dest->getPageNum() - 1;
else
{
Ref ref = dest->getPageRef();
vp.page = pdfdoc->findPage( ref.num, ref.gen ) - 1;
}
// get destination position (fill remaining Viewport fields)
switch ( dest->getKind() )
{
case destXYZ:
/* OD -> cvtUserToDev( dest->getLeft(), dest->getTop(), &X, &Y );
if ( dest->getChangeLeft() )
make hor change
if ( dest->getChangeTop() )
make ver change
if ( dest->getChangeZoom() )
make zoom change
*/ break;
case destFit:
case destFitB:
vp.fitWidth = true;
vp.fitHeight = true;
break;
case destFitH:
case destFitBH:
// read top, fit Width
vp.fitWidth = true;
break;
case destFitV:
case destFitBV:
// read left, fit Height
vp.fitHeight = true;
break;
case destFitR:
// read and fit left,bottom,right,top
break;
}
return vp;
}
QString GeneratorPDF::getDocumentInfo( const QString & data ) const
{
// [Albert] Code adapted from pdfinfo.cc on xpdf
Object info;
if ( !pdfdoc )
return i18n( "Unknown" );
pdfdoc->getDocInfo( &info );
if ( !info.isDict() )
return i18n( "Unknown" );
QCString result;
Object obj;
GString *s1;
GBool isUnicode;
Unicode u;
char buf[8];
int i, n;
Dict *infoDict = info.getDict();
UnicodeMap *uMap = globalParams->getTextEncoding();
if ( !uMap )
return i18n( "Unknown" );
if ( infoDict->lookup( data.latin1(), &obj )->isString() )
{
s1 = obj.getString();
if ( ( s1->getChar(0) & 0xff ) == 0xfe && ( s1->getChar(1) & 0xff ) == 0xff )
{
isUnicode = gTrue;
i = 2;
}
else
{
isUnicode = gFalse;
i = 0;
}
while ( i < obj.getString()->getLength() )
{
if ( isUnicode )
{
u = ( ( s1->getChar(i) & 0xff ) << 8 ) | ( s1->getChar(i+1) & 0xff );
i += 2;
}
else
{
u = s1->getChar(i) & 0xff;
++i;
}
n = uMap->mapUnicode( u, buf, sizeof( buf ) );
result += QCString( buf, n + 1 );
}
obj.free();
return result;
}
obj.free();
return i18n( "Unknown" );
}
QString GeneratorPDF::getDocumentDate( const QString & data ) const
{
// [Albert] Code adapted from pdfinfo.cc on xpdf
Object info;
if ( !pdfdoc )
return i18n( "Unknown Date" );
pdfdoc->getDocInfo( &info );
if ( !info.isDict() )
return i18n( "Unknown Date" );
Object obj;
char *s;
int year, mon, day, hour, min, sec;
Dict *infoDict = info.getDict();
UnicodeMap *uMap = globalParams->getTextEncoding();
if ( !uMap )
return i18n( "Unknown Date" );
if ( infoDict->lookup( data.latin1(), &obj )->isString() )
{
s = obj.getString()->getCString();
if ( s[0] == 'D' && s[1] == ':' )
s += 2;
if ( sscanf( s, "%4d%2d%2d%2d%2d%2d", &year, &mon, &day, &hour, &min, &sec ) == 6 )
{
QDate d( year, mon - 1, day );
QTime t( hour, min, sec );
if ( d.isValid() && t.isValid() )
return KGlobal::locale()->formatDateTime( QDateTime(d, t), false, true );
else
return s;
}
else
return s;
fputc( '\n', stdout );
obj.free();
//return result;
}
obj.free();
return i18n( "Unknown Date" );
}
/*
#include <qapplication.h>
#include <qevent.h>
#include <qimage.h>
ThumbnailGenerator::ThumbnailGenerator(PDFDoc *doc, QMutex *docMutex, int page, double ppp, QObject *o) : m_doc(doc), m_docMutex(docMutex), m_page(page), m_o(o), m_ppp(ppp)
{
}
int ThumbnailGenerator::getPage() const
{
return m_page;
}
void ThumbnailGenerator::run()
{
QCustomEvent *ce;
//QImage *i;
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff);
KPDFOutputDev odev(paperColor);
odev.startDoc(m_doc->getXRef());
m_docMutex->lock();
m_doc -> displayPage(&odev, m_page, m_ppp, m_ppp, 0, true, false);
m_docMutex->unlock();
ce = new QCustomEvent(65432);
//i = new QImage(odev.getImage());
//i -> detach();
//ce -> setData(i);
QApplication::postEvent(m_o, ce);
}
*/
/** TO BE IMPORTED:
void generateThumbnails(PDFDoc *doc);
void stopThumbnailGeneration();
protected slots:
void customEvent(QCustomEvent *e);
private slots:
void changeSelected(int i);
void emitClicked(int i);
signals:
void clicked(int);
private:
void generateNextThumbnail();
ThumbnailGenerator *m_tg;
void resizeThumbnails();
int m_nextThumbnail;
bool m_ignoreNext;
DELETE:
if (m_tg)
{
m_tg->wait();
delete m_tg;
}
void ThumbnailList::generateThumbnails(PDFDoc *doc)
{
m_nextThumbnail = 1;
m_doc = doc;
generateNextThumbnail();
}
void ThumbnailList::generateNextThumbnail()
{
if (m_tg)
{
m_tg->wait();
delete m_tg;
}
m_tg = new ThumbnailGenerator(m_doc, m_docMutex, m_nextThumbnail, QPaintDevice::x11AppDpiX(), this);
m_tg->start();
}
void ThumbnailList::stopThumbnailGeneration()
{
if (m_tg)
{
m_ignoreNext = true;
m_tg->wait();
delete m_tg;
m_tg = 0;
}
}
void ThumbnailList::customEvent(QCustomEvent *e)
{
if (e->type() == 65432 && !m_ignoreNext)
{
QImage *i = (QImage*)(e -> data());
setThumbnail(m_nextThumbnail, i);
m_nextThumbnail++;
if (m_nextThumbnail <= m_doc->getNumPages()) generateNextThumbnail();
else
{
m_tg->wait();
delete m_tg;
m_tg = 0;
}
}
m_ignoreNext = false;
}
*/

97
kpdf/generator_pdf.h Normal file
View file

@ -0,0 +1,97 @@
/***************************************************************************
* Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#ifndef _KPDF_GENERATOR_PDF_H_
#define _KPDF_GENERATOR_PDF_H_
#include <qmutex.h>
#include <qcolor.h>
#include <qstring.h>
#include "generator.h"
#include "document.h"
#include "link.h"
class PDFDoc;
class KPDFOutputDev;
/**
* @short A generator that builds contents from a PDF document.
*
* ...
*/
class GeneratorPDF : public Generator
{
public:
GeneratorPDF();
virtual ~GeneratorPDF();
// [INHERITED] load a document and fill up the pagesVector
bool loadDocument( const QString & fileName, QValueVector<KPDFPage*> & pagesVector );
// [INHERITED] document informations
const DocumentInfo & documentInfo();
// [INHERITED] perform actions on document / pages
bool print( KPrinter& printer );
bool requestPixmap( int id, KPDFPage * page, int width, int height, bool syncronous = false );
void requestTextPage( KPDFPage * page );
DocumentSynopsis& synopsis();
// [INHERITED] reparse configuration
bool reparseConfig();
// used by the KPDFOutputDev child
KPDFLinkGoto::Viewport decodeLinkViewport( class GString * namedDest, class LinkDest * dest );
private:
// private functions for accessing document informations via PDFDoc
QString getDocumentInfo( const QString & data ) const;
QString getDocumentDate( const QString & data ) const;
// private classes
QMutex docLock;
PDFDoc * pdfdoc;
KPDFOutputDev * kpdfOutputDev;
QColor paperColor;
bool docInfoDirty;
DocumentInfo docInfo;
DocumentSynopsis syn;
};
/*
#ifndef THUMBNAILGENERATOR_H
#define THUMBNAILGENERATOR_H
#include <qthread.h>
class QMutex;
class ThumbnailGenerator : public QThread
{
public:
ThumbnailGenerator(PDFDoc *doc, QMutex *docMutex, int page, double ppp, QObject *o);
int getPage() const;
protected:
void run();
private:
PDFDoc *m_doc;
QMutex *m_docMutex;
int m_page;
QObject *m_o;
double m_ppp;
};
#endif
*/
#endif

View file

@ -15,8 +15,8 @@
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include "GlobalParams.h"
#include "Error.h"
#include "xpdf/GlobalParams.h"
#include "xpdf/Error.h"
#include <qstring.h>

View file

@ -48,7 +48,7 @@
#include <kxmlguiclient.h>
#include <kxmlguifactory.h>
#include "GlobalParams.h"
#include "xpdf/GlobalParams.h"
#include "kpdf_part.h"
#include "pageview.h"
@ -172,7 +172,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName,
KStdAction::saveAs( this, SLOT( slotSaveFileAs() ), ac, "save" );
KStdAction::preferences( this, SLOT( slotPreferences() ), ac, "preferences" );
KStdAction::printPreview( this, SLOT( slotPrintPreview() ), ac );
m_showProperties = new KAction(i18n("Properties"), 0, this, SLOT(slotShowProperties()), ac, "properties");
m_showProperties->setEnabled( false );
@ -540,12 +540,12 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point)
else
popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 );
popup->insertItem( SmallIcon("viewmagfit"), i18n("Fit Width"), 2 );
popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 );
popup->setItemEnabled( 3, false );
//popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 );
//popup->setItemEnabled( 3, false );
}
/*
//Albert says: I have not ported this as i don't see it does anything
if ( d->mouseOnActiveRect )
if ( d->mouseOnRect ) // and rect->pointerType() == KDPFPageRect::Image ...
{
m_popup->insertItem( SmallIcon("filesave"), i18n("Save Image ..."), 4 );
m_popup->setItemEnabled( 4, false );
@ -562,16 +562,16 @@ void Part::slotShowMenu(const KPDFPage *page, const QPoint &point)
case 1:
m_document->toggleBookmark( page->number() );
break;
case 2:// zoom: Fit Width, columns: 1. setActions + relayout + setPage + update
case 2: // zoom: Fit Width, columns: 1. setActions + relayout + setPage + update
// (FIXME restore faster behavior and txt change as in old pageview implementation)
m_pageView->setZoomFitWidth();
m_document->setCurrentPage( page->number() );
break;
case 3: // ToDO switch to edit mode
m_pageView->slotSetMouseDraw();
break;
// case 3: // ToDO switch to edit mode
// m_pageView->slotSetMouseDraw();
// break;
}
delete popup;
}
void Part::slotShowProperties()

View file

@ -35,9 +35,6 @@ class KSelectAction;
class KAboutData;
class KPrinter;
class LinkAction;
class LinkDest;
class ThumbnailList;
class PageView;
class SearchWidget;

View file

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@ -7,31 +7,20 @@
* (at your option) any later version. *
***************************************************************************/
#ifndef THUMBNAILGENERATOR_H
#define THUMBNAILGENERATOR_H
// local includes
#include "link.h"
#include <qthread.h>
class QMutex;
class PDFDoc;
class ThumbnailGenerator : public QThread
KPDFLink::~KPDFLink()
{
public:
ThumbnailGenerator(PDFDoc *doc, QMutex *docMutex, int page, double ppp, QObject *o);
int getPage() const;
}
protected:
void run();
private:
PDFDoc *m_doc;
QMutex *m_docMutex;
int m_page;
QObject *m_o;
double m_ppp;
};
#endif
/*
void KPDFLink::copyString( char * &dest, const char * src ) const
{
if ( src )
{
dest = new char[ strlen(src) + 1 ];
strcpy( &dest[0], src );
}
}
*/

115
kpdf/link.h Normal file
View file

@ -0,0 +1,115 @@
/***************************************************************************
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#ifndef _KPDF_LINK_H_
#define _KPDF_LINK_H_
#include <qstring.h>
#include <qrect.h>
/**
* @short Encapsulates data that describes a link.
* ### MERGE: MOVE definition/implementation to kpdflink.h/.cpp
* ### TODO: recomment
*/
class KPDFLink
{
public:
// get link type (inherited classes mustreturn an unique identifier)
enum LinkType { Goto, Execute, Browse, Action, Movie };
virtual LinkType linkType() const = 0;
// virtual destructor (remove warnings)
virtual ~KPDFLink();
};
class KPDFLinkGoto : public KPDFLink
{
public:
// define a 'Viewport' TODO improve this
struct Viewport {
int page;
bool fitWidth, fitHeight;
QRect rectPercent;
};
// query for goto parameters
bool isExternal() const { return !m_extFileName.isEmpty(); }
const QString & fileName() const { return m_extFileName; }
const Viewport & destViewport() const { return m_vp; }
// create a KPDFLink_Goto
KPDFLinkGoto( QString extFileName, Viewport vp ) { m_extFileName = extFileName; m_vp = vp; }
LinkType linkType() const { return Goto; }
private:
QString m_extFileName;
Viewport m_vp;
};
class KPDFLinkExecute : public KPDFLink
{
public:
// query for filename / parameters
const QString & fileName() const { return m_fileName; }
const QString & parameters() const { return m_parameters; }
// create a KPDFLink_Execute
KPDFLinkExecute( const QString & file, const QString & params ) { m_fileName = file; m_parameters = params; }
LinkType linkType() const { return Execute; }
private:
QString m_fileName;
QString m_parameters;
};
class KPDFLinkBrowse : public KPDFLink
{
public:
// query for URL
const QString & url() const { return m_url; }
// create a KPDFLink_Browse
KPDFLinkBrowse( QString url ) { m_url = url; }
LinkType linkType() const { return Browse; }
private:
QString m_url;
};
class KPDFLinkAction : public KPDFLink
{
public:
// define types of actions
enum ActionType { PageFirst, PagePrev, PageNext, PageLast, HistoryBack, HistoryForward, Quit };
// query for action type
ActionType actionType() const { return m_type; }
// create a KPDFLink_Action
KPDFLinkAction( enum ActionType actionType ) { m_type = actionType; }
LinkType linkType() const { return Action; }
private:
ActionType m_type;
};
class KPDFLinkMovie : public KPDFLink //### REDO THIS ###
{
public:
KPDFLinkMovie() {};
LinkType linkType() const { return Movie; }
};
#endif

View file

@ -15,17 +15,20 @@
#include <qpainter.h>
#include <qmap.h>
#include <kimageeffect.h>
#include <kdebug.h>
// system includes
#include <string.h>
// local includes
#include "Link.h"
#include "TextOutputDev.h"
#include "settings.h"
#include "page.h"
#include "link.h"
#include "settings.h"
#include "xpdf/TextOutputDev.h"
/** class KPDFPage **/
KPDFPage::KPDFPage( uint page, float w, float h, int r )
: m_number( page ), m_rotation( r ), m_attributes( 0 ),
m_width( w ), m_height( h ), m_sLeft( 0 ), m_sTop( 0 ),
@ -41,7 +44,7 @@ KPDFPage::KPDFPage( uint page, float w, float h, int r )
KPDFPage::~KPDFPage()
{
deletePixmapsAndLinks();
deletePixmapsAndRects();
delete m_text;
}
@ -54,26 +57,29 @@ bool KPDFPage::hasPixmap( int id, int width, int height ) const
return p ? ( p->width() == width && p->height() == height ) : false;
}
bool KPDFPage::hasLink( int mouseX, int mouseY ) const
bool KPDFPage::hasSearchPage() const
{
if ( m_links.count() < 1 )
return m_text != 0;
}
bool KPDFPage::hasRect( int mouseX, int mouseY ) const
{
if ( m_rects.count() < 1 )
return false;
QValueList< KPDFLink * >::const_iterator it = m_links.begin(), end = m_links.end();
QValueList< KPDFPageRect * >::const_iterator it = m_rects.begin(), end = m_rects.end();
for ( ; it != end; ++it )
if ( (*it)->contains( mouseX, mouseY ) )
return true;
return false;
}
bool KPDFPage::hasActiveRect( int mouseX, int mouseY ) const
const KPDFPageRect * KPDFPage::getRect( int mouseX, int mouseY ) const
{
if ( m_rects.count() < 1 )
return false;
QValueList< KPDFActiveRect * >::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 )
if ( (*it)->contains( mouseX, mouseY ) )
return true;
return false;
return *it;
return 0;
}
const QString KPDFPage::getTextInRect( const QRect & rect, double zoom ) const
@ -88,15 +94,6 @@ const QString KPDFPage::getTextInRect( const QRect & rect, double zoom ) const
return QString( text->getCString() );
}
const KPDFLink * KPDFPage::getLink( int mouseX, int mouseY ) const
{
QValueList< KPDFLink * >::const_iterator it = m_links.begin(), end = m_links.end();
for ( ; it != end; ++it )
if ( (*it)->contains( mouseX, mouseY ) )
return *it;
return 0;
}
bool KPDFPage::hasText( const QString & text, bool strictCase, bool fromTop )
{
@ -131,42 +128,88 @@ void KPDFPage::setSearchPage( TextPage * tp )
m_text = tp;
}
void KPDFPage::setLinks( const QValueList<KPDFLink *> links )
void KPDFPage::setRects( const QValueList< KPDFPageRect * > rects )
{
QValueList< KPDFLink * >::iterator it = m_links.begin(), end = m_links.end();
for ( ; it != end; ++it )
delete *it;
m_links = links;
}
void KPDFPage::setActiveRects( const QValueList<KPDFActiveRect *> rects )
{
QValueList< KPDFActiveRect * >::iterator it = m_rects.begin(), end = m_rects.end();
QValueList< KPDFPageRect * >::iterator it = m_rects.begin(), end = m_rects.end();
for ( ; it != end; ++it )
delete *it;
m_rects = rects;
}
void KPDFPage::deletePixmapsAndLinks()
void KPDFPage::deletePixmapsAndRects()
{
// delete all stored pixmaps
QMap<int,QPixmap *>::iterator it = m_pixmaps.begin(), end = m_pixmaps.end();
for ( ; it != end; ++it )
delete *it;
m_pixmaps.clear();
// delete Links
QValueList< KPDFLink * >::iterator lIt = m_links.begin(), lEnd = m_links.end();
for ( ; lIt != lEnd; ++lIt )
delete *lIt;
m_links.clear();
// delete ActiveRects
QValueList< KPDFActiveRect * >::iterator rIt = m_rects.begin(), rEnd = m_rects.end();
// delete PageRects
QValueList< KPDFPageRect * >::iterator rIt = m_rects.begin(), rEnd = m_rects.end();
for ( ; rIt != rEnd; ++rIt )
delete *rIt;
m_rects.clear();
}
/** class KPDFPageRect **/
KPDFPageRect::KPDFPageRect( int l, int t, int r, int b )
: m_pointerType( NoPointer ), m_pointer( 0 )
{
// assign coordinates swapping them if negative width or height
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()
{
deletePointer();
}
bool KPDFPageRect::contains( int x, int y ) const
{
return (x > m_xMin) && (x < m_xMax) && (y > m_yMin) && (y < m_yMax);
}
QRect KPDFPageRect::geometry() const
{
return QRect( m_xMin, m_yMin, m_xMax - m_xMin, m_yMax - m_yMin );
}
void KPDFPageRect::setPointer( void * object, enum PointerType pType )
{
deletePointer();
m_pointer = object;
m_pointerType = pType;
}
KPDFPageRect::PointerType KPDFPageRect::pointerType() const
{
return m_pointerType;
}
const void * KPDFPageRect::pointer() const
{
return m_pointer;
}
void KPDFPageRect::deletePointer()
{
if ( !m_pointer )
return;
if ( m_pointerType == Link )
delete static_cast<KPDFLink*>( m_pointer );
else
kdDebug() << "Object deletion not implemented for type '"
<< m_pointerType << "' ." << endl;
}
/** class PagePainter **/
void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags,
QPainter * destPainter, const QRect & limits, int width, int height )
{
@ -275,56 +318,36 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags,
backPixmap->convertFromImage( backImage );
}
// visually enchance links active area if requested
if ( ( flags & EnhanceLinks ) && Settings::highlightLinks() )
// visually enchance links and images if requested
bool hLinks = ( flags & EnhanceLinks ) && Settings::highlightLinks();
bool hImages = ( flags & EnhanceImages ) && Settings::highlightImages();
if ( hLinks || hImages )
{
QColor normalColor = QApplication::palette().active().highlight();
QColor lightColor = normalColor.light( 140 );
// enlarging limits for intersection is like growing the 'linkGeometry' below
// enlarging limits for intersection is like growing the 'rectGeometry' below
QRect limitsEnlarged = limits;
limitsEnlarged.addCoords( -2, -2, 2, 2 );
// draw links that are inside the 'limits' paint region as opaque rects
QValueList< KPDFLink * >::const_iterator lIt = page->m_links.begin(), lEnd = page->m_links.end();
// draw rects that are inside the 'limits' paint region as opaque rects
QValueList< KPDFPageRect * >::const_iterator lIt = page->m_rects.begin(), lEnd = page->m_rects.end();
for ( ; lIt != lEnd; ++lIt )
{
QRect linkGeometry = (*lIt)->geometry();
if ( linkGeometry.intersects( limitsEnlarged ) )
KPDFPageRect * rect = *lIt;
if ( (hLinks && rect->pointerType() == KPDFPageRect::Link) ||
(hImages && rect->pointerType() == KPDFPageRect::Image) )
{
// expand rect and draw inner border
linkGeometry.addCoords( -1,-1,1,1 );
p->setPen( lightColor );
p->drawRect( linkGeometry );
// expand rect to draw outer border
linkGeometry.addCoords( -1,-1,1,1 );
p->setPen( normalColor );
p->drawRect( linkGeometry );
}
}
}
// visually enchance image borders if requested
if ( ( flags & EnhanceRects ) && Settings::highlightImages() )
{
QColor normalColor = QApplication::palette().active().highlight();
QColor lightColor = normalColor.light( 140 );
// enlarging limits for intersection is like growing the 'linkGeometry' below
QRect limitsEnlarged = limits;
limitsEnlarged.addCoords( -2, -2, 2, 2 );
// draw links that are inside the 'limits' paint region as opaque rects
QValueList< KPDFActiveRect * >::const_iterator rIt = page->m_rects.begin(), rEnd = page->m_rects.end();
for ( ; rIt != rEnd; ++rIt )
{
QRect rectGeometry = (*rIt)->geometry();
if ( rectGeometry.intersects( limitsEnlarged ) )
{
// expand rect and draw inner border
rectGeometry.addCoords( -1,-1,1,1 );
p->setPen( lightColor );
p->drawRect( rectGeometry );
// expand rect to draw outer border
rectGeometry.addCoords( -1,-1,1,1 );
p->setPen( normalColor );
p->drawRect( rectGeometry );
QRect rectGeometry = rect->geometry();
if ( rectGeometry.intersects( limitsEnlarged ) )
{
// expand rect and draw inner border
rectGeometry.addCoords( -1,-1,1,1 );
p->setPen( lightColor );
p->drawRect( rectGeometry );
// expand rect to draw outer border
rectGeometry.addCoords( -1,-1,1,1 );
p->setPen( normalColor );
p->drawRect( rectGeometry );
}
}
}
}
@ -354,161 +377,3 @@ void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags,
delete backPixmap;
}
}
KPDFLink::KPDFLink( LinkAction * a )
: m_type( Unknown ), x_min( 0 ), x_max( 0 ), y_min( 0 ), y_max( 0 ),
m_dest( 0 ), m_destNamed( 0 ), m_fileName( 0 ), m_parameters( 0 ), m_uri( 0 )
{
// set link action params processing (XPDF)LinkAction
switch ( a->getKind() )
{
case actionGoTo: {
LinkGoTo * g = (LinkGoTo *) a;
m_type = Goto;
// copy link dest (LinkDest class)
LinkDest * d = g->getDest();
m_dest = d ? d->copy() : 0;
// copy link namedDest (const char *)
GString * nd = g->getNamedDest();
copyString( m_destNamed, nd ? nd->getCString() : 0 );
} break;
case actionGoToR: {
m_type = Goto;
LinkGoToR * g = (LinkGoToR *) a;
// copy link file (const char *)
copyString( m_fileName, g->getFileName()->getCString() );
// copy link dest (LinkDest class)
LinkDest * d = g->getDest();
m_dest = d ? d->copy() : 0;
// copy link namedDest (const char *)
GString * nd = g->getNamedDest();
copyString( m_destNamed, nd ? nd->getCString() : 0 );
} break;
case actionLaunch: {
m_type = Execute;
LinkLaunch * e = (LinkLaunch *)a;
// copy name and parameters of the file to open(in case of PDF)/launch
copyString( m_fileName, e->getFileName()->getCString() );
GString * par = e->getParams();
copyString( m_parameters, par ? par->getCString() : 0 );
} break;
case actionURI:
m_type = URI;
// copy URI (const char *)
copyString( m_uri, ((LinkURI *)a)->getURI()->getCString() );
break;
case actionNamed:
m_type = Named;
// copy Action Name (const char * like Quit, Next, Back, etc..)
copyString( m_uri, ((LinkNamed *)a)->getName()->getCString() );
break;
case actionMovie: {
m_type = Movie;
LinkMovie * m = (LinkMovie *) a;
// copy Movie parameters (2 IDs and a const char *)
Ref * r = m->getAnnotRef();
m_refNum = r->num;
m_refGen = r->gen;
copyString( m_uri, m->getTitle()->getCString() );
} break;
case actionUnknown:
break;
}
}
void KPDFLink::setGeometry( int l, int t, int r, int b )
{
// 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;
}
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 ) const
{
if ( src )
{
dest = new char[ strlen(src) + 1 ];
strcpy( &dest[0], src );
}
}
QRect KPDFLink::geometry() const
{
return QRect( x_min, y_min, x_max - x_min, y_max - y_min );
}
KPDFLink::LinkType KPDFLink::type() const
{
return m_type;
}
const LinkDest * KPDFLink::getDest() const
{
return m_dest;
}
const char * KPDFLink::getNamedDest() const
{
return m_destNamed;
}
const char * KPDFLink::getFileName() const
{
return m_fileName;
}
const char * KPDFLink::getParameters() const
{
return m_parameters;
}
const char * KPDFLink::getName() const
{
return m_uri;
}
const char * KPDFLink::getURI() const
{
return m_uri;
}
KPDFActiveRect::KPDFActiveRect(int left, int top, int width, int height)
: m_left(left), m_top(top), m_right(left + width), m_bottom(top + height)
{
}
bool KPDFActiveRect::contains(int x, int y)
{
return (x > m_left) && (x < m_right) && (y > m_top) && (y < m_bottom);
}
QRect KPDFActiveRect::geometry() const
{
return QRect( m_left, m_top, m_right - m_left, m_bottom - m_top );
}

View file

@ -16,14 +16,12 @@
class QPainter;
class QPixmap;
class TextPage;
class LinkAction;
class LinkDest;
class KPDFLink;
class KPDFActiveRect;
class KPDFPageRect;
/**
* @short Collector for all the data belonging to a page.
* ### MERGE: definition and implementation must be moved to kpdfpage.h/.cpp
* ### RECOMMENT
*
* The KPDFPage class contains pixmaps (referenced using obsedvers id as key),
* a search page (a class used internally for searching data), link classes
@ -48,11 +46,10 @@ class KPDFPage
inline float ratio() const { return m_height / m_width; }
bool hasPixmap( int id, int width, int height ) const;
bool hasSearchPage() const { return m_text != 0; }
bool hasLink( int mouseX, int mouseY ) const;
bool hasActiveRect( int mouseX, int mouseY ) const;
bool hasSearchPage() const;
bool hasRect( int mouseX, int mouseY ) const;
const KPDFPageRect * getRect( int mouseX, int mouseY ) const;
const QString getTextInRect( const QRect & rect, double zoom = 1.0 ) const;
const KPDFLink * getLink( int mouseX, int mouseY ) const;
// operations (by KPDFDocument)
inline void setAttribute( int att ) { m_attributes |= att; }
@ -63,9 +60,8 @@ class KPDFPage
// set contents (by KPDFDocument)
void setPixmap( int id, QPixmap * pixmap );
void setSearchPage( TextPage * text );
void setLinks( const QValueList<KPDFLink *> links );
void setActiveRects( const QValueList<KPDFActiveRect *> rects );
void deletePixmapsAndLinks();
void setRects( const QValueList< KPDFPageRect * > rects );
void deletePixmapsAndRects();
private:
friend class PagePainter;
@ -75,10 +71,54 @@ class KPDFPage
QMap< int, QPixmap * > m_pixmaps;
TextPage * m_text;
QValueList< KPDFLink * > m_links;
QValueList< KPDFActiveRect * > m_rects;
QValueList< KPDFPageRect * > m_rects;
};
/**
* @short A rect on the page that may contain an object.
*
* This class describes a rect (geometrical coordinates) and may hold a
* pointer to an associated object. An object is reparented to this class
* and deleted when this class is deleted.
*
* Objects are stored and read as 'void pointers' so you have to perform
* the cast on the code that handles the object using information provided
* by pointerType().
*
* Type / Class correspondency tab:
* - NoPointer : '' : no object is stored
* - Link : class KPDFLink : description of a link
* - Image : class KPDFImage : description of an image
*
*/
class KPDFPageRect
{
public:
KPDFPageRect( int left, int top, int right, int bottom );
~KPDFPageRect();
// query geometric properties
bool contains( int x, int y ) const;
QRect geometry() const; //TODO add intersects( qrect )
// set a pointer to data associated to this rect
enum PointerType { NoPointer, Link, Image };
void setPointer( void * object, enum PointerType pType );
// query type and get a const pointer to the stored object
PointerType pointerType() const;
const void * pointer() const;
private:
void deletePointer();
int m_xMin, m_xMax, m_yMin, m_yMax;
PointerType m_pointerType;
void * m_pointer;
};
/**
* @short Paints a KPDFPage to an open painter using given flags.
* ### MERGE: since this file will be empty, we might consider renaming
@ -90,7 +130,7 @@ class PagePainter
// list of flags passed to the painting function. by OR-ing those flags
// you can decide wether or not to permit drawing of a certain feature.
enum PagePainterFlags { Accessibility = 1, EnhanceLinks = 2,
EnhanceRects = 4, Highlight = 8 };
EnhanceImages = 4, Highlight = 8 };
// draw (using painter 'p') the 'page' requested by 'id' using features
// in 'flags'. 'limits' is the bounding rect of the paint operation,
@ -100,77 +140,4 @@ class PagePainter
QPainter * p, const QRect & limits, int width = -1, int height = -1 );
};
/**
* @short Encapsulates data that describes a link.
* ### MERGE: MOVE definition/implementation to kpdflink.h/.cpp
* ### NOTE: KPDFActiveRect and KPDFLink SHOULD BE MERGED !!
*
* 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
{
public:
KPDFLink( LinkAction * PDFAction );
~KPDFLink();
// set geometry (only links collected KPDFPage(s))
void setGeometry( int left, int top, int right, int bottom );
// query / others
bool contains( int x, int y ) const;
void copyString( char * &dest, const char * src ) const;
QRect geometry() const; //TODO add intersects( qrect )
// action queries
enum LinkType { Goto, Execute, URI, Named, Movie, Unknown };
LinkType type() const;
const LinkDest * getDest() const; //1
const char * getNamedDest() const; //1
const char * getFileName() const; //1,2
const char * getParameters() const; //2
const char * getName() const; //3
const char * getURI() const; //4
private:
// general
LinkType m_type;
int x_min, x_max, y_min, y_max;
// actions related
LinkDest * m_dest;
char * m_destNamed;
char * m_fileName;
char * m_parameters;
char * m_uri;
int m_refNum, m_refGen;
};
/**
* @short Describes an 'active' rectange on the page.
* ### MERGE: MOVE definition/implementation to kpdflink.h/.cpp
* ### NOTE: KPDFActiveRect and KPDFLink SHOULD BE MERGED !!
*
* ...
*/
class KPDFActiveRect
{
public:
KPDFActiveRect(int left, int top, int width, int height);
// query
bool contains(int x, int y);
QRect geometry() const;
private:
int m_left, m_top, m_right, m_bottom;
};
#endif

View file

@ -39,6 +39,7 @@
#include "pageview.h"
#include "pageviewutils.h"
#include "page.h"
#include "link.h"
#include "settings.h"
#define ROUND(x) (int(x + 0.5))
@ -60,8 +61,7 @@ public:
QPoint mouseGrabPos;
QPoint mouseStartPos;
int mouseMidStartY;
bool mouseOnLink;
bool mouseOnActiveRect;
bool mouseOnRect;
QRect mouseSelectionRect;
// other stuff
@ -105,8 +105,7 @@ PageView::PageView( QWidget *parent, KPDFDocument *document )
d->zoomFactor = 1.0;
d->mouseMode = MouseNormal;
d->mouseMidStartY = -1;
d->mouseOnLink = false;
d->mouseOnActiveRect = false;
d->mouseOnRect = false;
d->delayTimer = 0;
d->scrollTimer = 0;
d->scrollIncrement = 0;
@ -126,6 +125,9 @@ PageView::PageView( QWidget *parent, KPDFDocument *document )
// conntect the padding of the viewport to pixmaps requests
connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestVisiblePixmaps(int, int)) );
// ### [RELEASE: REMOVE] show initial warning for dev_version > 2004-Dec-04
d->messageWindow->display( "We're in progress of abstracting code. You will see some REGRESSIONS at this stage.", PageViewMessage::Warning, 8000 );
// set a corner button to resize the view to the page size
// QPushButton * resizeButton = new QPushButton( viewport() );
// resizeButton->setPixmap( SmallIcon("crop") );
@ -255,10 +257,10 @@ void PageView::pageSetup( const QValueVector<KPDFPage*> & pageSet, bool document
d->dirtyLayout = true;
// OSD to display pages
if ( documentChanged && !Settings::hideOSD() )
if ( documentChanged && pageSet.count() > 0 && !Settings::hideOSD() )
d->messageWindow->display(
i18n(" Loaded a 1 page document.",
" Loaded a %n page document.",
i18n(" Loaded a one page document.",
" Loaded a %n pages document.",
pageSet.count() ),
PageViewMessage::Info, 4000 );
}
@ -502,8 +504,8 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e )
d->mouseMidStartY = e->globalPos().y();
d->zoomFactor *= ( 1.0 + ( (double)deltaY / 500.0 ) );
updateZoom( ZoomRefreshCurrent );
// uncomment following line to force a complete redraw
//viewport()->repaint();
// uncomment following line to force a complete redraw
viewport()->repaint( false );
return;
}
@ -537,21 +539,10 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e )
int pageX = e->x() - pageItem->geometry().left(),
pageY = e->y() - pageItem->geometry().top();
// check if over a KPDFActiveRect
bool onActiveRect = pageItem->page()->hasActiveRect( pageX, pageY );
if ( onActiveRect != d->mouseOnActiveRect )
{
d->mouseOnActiveRect = onActiveRect;
setCursor( onActiveRect ? pointingHandCursor : arrowCursor );
}
// check if over a KPDFLink
bool onLink = pageItem->page()->hasLink( pageX, pageY );
if ( onLink != d->mouseOnLink )
{
d->mouseOnLink = onLink;
setCursor( onLink ? pointingHandCursor : arrowCursor );
}
// check if over a KPDFPageRect
bool onRect = pageItem->page()->hasRect( pageX, pageY );
if ( onRect != d->mouseOnRect )
setCursor( (d->mouseOnRect = onRect) ? pointingHandCursor : arrowCursor );
}
}
break;
@ -586,8 +577,8 @@ void PageView::contentsMousePressEvent( QMouseEvent * e )
if ( leftButton )
{
d->mouseStartPos = e->globalPos();
d->mouseGrabPos = d->mouseOnLink ? QPoint() : d->mouseStartPos;
if ( !d->mouseOnLink )
d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mouseStartPos;
if ( !d->mouseOnRect )
setCursor( sizeAllCursor );
}
break;
@ -622,12 +613,22 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
PageViewItem * pageItem = pickItemOnPoint( e->x(), e->y() );
if ( leftButton && pageItem )
{
if ( d->mouseOnLink )
const KPDFPageRect * rect = pageItem->page()->getRect(
e->x() - pageItem->geometry().left(),
e->y() - pageItem->geometry().top()
);
if ( rect )
{
// activate link
int linkX = e->x() - pageItem->geometry().left(),
linkY = e->y() - pageItem->geometry().top();
d->document->processLink( pageItem->page()->getLink( linkX, linkY ) );
// release over a link
if ( rect->pointerType() == KPDFPageRect::Link )
{
const KPDFLink * link = static_cast< const KPDFLink * >( rect->pointer() );
d->document->processLink( link );
}
// release over an image
if ( rect->pointerType() == KPDFPageRect::Image )
{
}
}
else
{
@ -872,7 +873,7 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect )
QRect pixmapRect = contentsRect.intersect( pixmapGeometry );
pixmapRect.moveBy( -pixmapGeometry.left(), -pixmapGeometry.top() );
int flags = PagePainter::Accessibility | PagePainter::EnhanceLinks |
PagePainter::EnhanceRects | PagePainter::Highlight;
PagePainter::EnhanceImages | PagePainter::Highlight;
PagePainter::paintPageOnPainter( item->page(), PAGEVIEW_ID, flags, p, pixmapRect,
pixmapGeometry.width(), pixmapGeometry.height() );
}

View file

@ -21,7 +21,7 @@
<cstring>textLabel1_3_2_3_6</cstring>
</property>
<property name="text">
<string>PDF version:</string>
<string>Format:</string>
</property>
</widget>
<widget class="QLabel" row="8" column="0">
@ -50,6 +50,12 @@
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
<spacer row="6" column="2">
<property name="name">
@ -61,6 +67,12 @@
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
<widget class="QLabel" row="5" column="0">
<property name="name">

View file

@ -19,18 +19,17 @@ propertiesDialog::propertiesDialog(QWidget *parent, KPDFDocument *doc) : KDialog
{
properties *p = new properties(this);
setMainWidget(p);
const DocumentInfo & info = doc->documentInfo();
p->pagesValue->setText(QString::number(doc->pages()));
p->authorValue->setText(doc->author());
p->titleValue->setText(doc->title());
p->subjectValue->setText(doc->subject());
p->keywordsValue->setText(doc->keywords());
p->producerValue->setText(doc->producer());
p->creatorValue->setText(doc->creator());
if (doc->optimized()) p->optimizedValue->setText(i18n("Yes"));
else p->optimizedValue->setText(i18n("No"));
if (doc->encrypted()) p->securityValue->setText(i18n("Encrypted"));
else p->securityValue->setText(i18n("No"));
p->versionValue->setText(QString::number(doc->PDFversion()));
p->createdValue->setText(doc->creationDate());
p->modifiedValue->setText(doc->modificationDate());
p->authorValue->setText( info.author );
p->titleValue->setText( info.title );
p->subjectValue->setText( info.subject );
p->keywordsValue->setText( info.keywords );
p->producerValue->setText( info.producer );
p->creatorValue->setText( info.creator );
p->optimizedValue->setText( info.optimization );
p->securityValue->setText( info.encryption );
p->versionValue->setText( info.format + " v." + info.formatVersion );
p->createdValue->setText( info.creationDate );
p->modifiedValue->setText( info.modificationDate );
}

View file

@ -1,46 +0,0 @@
/***************************************************************************
* Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <qapplication.h>
#include <qevent.h>
#include <qimage.h>
#include <qmutex.h>
#include "PDFDoc.h"
#include "QOutputDev.h"
#include "thumbnailgenerator.h"
ThumbnailGenerator::ThumbnailGenerator(PDFDoc *doc, QMutex *docMutex, int page, double ppp, QObject *o) : m_doc(doc), m_docMutex(docMutex), m_page(page), m_o(o), m_ppp(ppp)
{
}
int ThumbnailGenerator::getPage() const
{
return m_page;
}
void ThumbnailGenerator::run()
{
QCustomEvent *ce;
//QImage *i;
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff);
KPDFOutputDev odev(paperColor);
odev.startDoc(m_doc->getXRef());
m_docMutex->lock();
m_doc -> displayPage(&odev, m_page, m_ppp, m_ppp, 0, true, false);
m_docMutex->unlock();
ce = new QCustomEvent(65432);
//i = new QImage(odev.getImage()); FIXME commented because the ODEV is changing
//i -> detach();
//ce -> setData(i);
QApplication::postEvent(m_o, ce);
}

View file

@ -139,8 +139,9 @@ QString TOC::getTitle(Unicode *u, int length, UnicodeMap *uMap) const
void TOC::slotExecuted(QListViewItem *i)
{
TOCItem *ti = dynamic_cast<TOCItem*>(i);
KPDFLink l( ti->getAction() );
m_document->processLink( &l );
//FIXME
//KPDFLink l( ti->getAction() );
//m_document->processLink( &l );
}
#include "toc.moc"