Commit 5f4236d8 authored by Enrico Ros's avatar Enrico Ros

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
parent 18e7d798
......@@ -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
......
......@@ -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
......@@ -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;
};
......
......@@ -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)
......
This diff is collapsed.
......@@ -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
/***************************************************************************
* 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
/***************************************************************************
* 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");