From 5f4236d8010d743a04543f993c5d1895a8bcb6b5 Mon Sep 17 00:00:00 2001 From: Enrico Ros Date: Fri, 10 Dec 2004 16:04:45 +0000 Subject: [PATCH] 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 --- kpdf/Makefile.am | 2 +- kpdf/QOutputDev.cpp | 165 +++-- kpdf/QOutputDev.h | 32 +- kpdf/TODO | 4 +- kpdf/document.cpp | 836 ++++++------------------ kpdf/document.h | 57 +- kpdf/generator.h | 55 ++ kpdf/generator_pdf.cpp | 548 ++++++++++++++++ kpdf/generator_pdf.h | 97 +++ kpdf/kpdf_error.cpp | 4 +- kpdf/kpdf_part.cpp | 20 +- kpdf/kpdf_part.h | 3 - kpdf/{thumbnailgenerator.h => link.cpp} | 41 +- kpdf/link.h | 115 ++++ kpdf/page.cpp | 345 +++------- kpdf/page.h | 141 ++-- kpdf/pageview.cpp | 65 +- kpdf/properties.ui | 14 +- kpdf/propertiesdialog.cpp | 25 +- kpdf/thumbnailgenerator.cpp | 46 -- kpdf/toc.cpp | 5 +- 21 files changed, 1439 insertions(+), 1181 deletions(-) create mode 100644 kpdf/generator.h create mode 100644 kpdf/generator_pdf.cpp create mode 100644 kpdf/generator_pdf.h rename kpdf/{thumbnailgenerator.h => link.cpp} (54%) create mode 100644 kpdf/link.h delete mode 100644 kpdf/thumbnailgenerator.cpp diff --git a/kpdf/Makefile.am b/kpdf/Makefile.am index 29d688429..d1748571a 100644 --- a/kpdf/Makefile.am +++ b/kpdf/Makefile.am @@ -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 diff --git a/kpdf/QOutputDev.cpp b/kpdf/QOutputDev.cpp index f951ad89e..566d7c399 100644 --- a/kpdf/QOutputDev.cpp +++ b/kpdf/QOutputDev.cpp @@ -23,17 +23,21 @@ #include #include -#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 diff --git a/kpdf/QOutputDev.h b/kpdf/QOutputDev.h index 5265e4dbb..0990e1ae2 100644 --- a/kpdf/QOutputDev.h +++ b/kpdf/QOutputDev.h @@ -19,21 +19,25 @@ #pragma interface #endif -#include "SplashOutputDev.h" -#include "Link.h" +#include +#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; }; diff --git a/kpdf/TODO b/kpdf/TODO index 19e3c0bcf..60cd36f01 100644 --- a/kpdf/TODO +++ b/kpdf/TODO @@ -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) diff --git a/kpdf/document.cpp b/kpdf/document.cpp index 35cc67ced..17f0f8af9 100644 --- a/kpdf/document.cpp +++ b/kpdf/document.cpp @@ -9,170 +9,46 @@ ***************************************************************************/ // qt/kde/system includes -#include #include #include #include -#include #include #include #include #include #include #include -#include -#include -#include -#include -#include #include -#include -#include #include -#include +#include +#include // local includes -#include "ErrorCodes.h" -#include "PDFDoc.h" -#include "PSOutputDev.h" -#include "QOutputDev.h" -#include "UnicodeMap.h" - #include "document.h" #include "page.h" +#include "link.h" #include "settings.h" - -/* Notes: -- FIXME event queuing to avoid flow loops (!!?) maybe avoided by the - warning to not call something 'active' inside an observer method. -*/ +#include "generator_pdf.h" // PDF generator +//#include "generator_ps.H" // PS generator // structure used internally by KPDFDocument for local variables storage class KPDFDocumentPrivate { -public: - // Albert says: I've put that two functions here but they could go - // elsewhere, i leave it up to you if you want to change them Enrico - QString getDocumentInfo(const QString &data) const - { - // Code adapted from pdfinfo.cc on xpdf - Object info; - if (pdfdoc) - { - pdfdoc->getDocInfo(&info); - if (info.isDict()) - { - 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"); - } - else return i18n("Unknown"); - } - else return i18n("Unknown"); - } - - QString getDocumentDate(const QString &data) const - { - // Code adapted from pdfinfo.cc on xpdf - Object info; - if (pdfdoc) - { - pdfdoc->getDocInfo(&info); - if (info.isDict()) - { - Object obj; - char *s; - int year, mon, day, hour, min, sec; - Dict *infoDict = info.getDict(); - UnicodeMap *uMap = globalParams->getTextEncoding(); - - if (!uMap) return i18n("Unknown"); - - 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"); - } - else return i18n("Unknown"); - } - else return i18n("Unknown"); - } - - // document related - QMutex docLock; - PDFDoc * pdfdoc; - KPDFOutputDev * kpdfOutputDev; - int currentPage; - QRect currentViewport; - QValueVector< KPDFPage* > pages; - QColor paperColor; + public: + // find related + QString searchText; + bool searchCase; + int searchPage; + // filtering related + QString filterText; + bool filterCase; - // find related - QString searchText; - bool searchCase; - int searchPage; - // filtering related - QString filterText; - bool filterCase; + // cached stuff + int currentPage; + DocumentInfo noDocumentInfo; - // observers related (note: won't delete oservers) - QMap< int, KPDFDocumentObserver* > observers; + // observers related (note: won't delete oservers) + QMap< int, KPDFDocumentObserver* > observers; }; #define foreachObserver( cmd ) {\ @@ -180,24 +56,17 @@ public: QMap::iterator end = d->observers.end();\ for ( ; it != end ; ++ it ) { (*it)-> cmd ; } } -/* - * KPDFDocument class - */ KPDFDocument::KPDFDocument() + : generator( 0 ), d( new KPDFDocumentPrivate ) { - d = new KPDFDocumentPrivate; - d->pdfdoc = 0; d->currentPage = -1; d->searchPage = -1; - d->kpdfOutputDev = 0; - // create the outputdev - reparseConfig(); + d->noDocumentInfo.title = i18n( "No document opened!" ); } KPDFDocument::~KPDFDocument() { closeDocument(); - delete d->kpdfOutputDev; delete d; } @@ -208,106 +77,52 @@ bool KPDFDocument::openDocument( const QString & docFile ) QFile fileReadTest( docFile ); if ( !fileReadTest.open( IO_ReadOnly ) ) return false; - long fileSize = fileReadTest.size(); fileReadTest.close(); - // free internal data + // reset internal status and frees memory closeDocument(); - GString *filename = new GString( QFile::encodeName( docFile ) ); - delete d->pdfdoc; - d->pdfdoc = new PDFDoc( filename, 0, 0 ); - - if ( !d->pdfdoc->isOk() ) - { - if (d->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()); - d->pdfdoc = new PDFDoc(filename, pwd2, pwd2); - delete pwd2; - correct = d->pdfdoc->isOk(); - if (!correct && d->pdfdoc->getErrorCode() != errEncrypted) - { - delete d->pdfdoc; - d->pdfdoc = 0; - return false; - } - } - else - { - delete d->pdfdoc; - d->pdfdoc = 0; - return false; - } - } - } - else - { - delete d->pdfdoc; - d->pdfdoc = 0; - return false; - } - } - - // initialize output device for rendering current pdf - d->kpdfOutputDev->startDoc( d->pdfdoc->getXRef() ); - - // build Pages (currentPage was set -1 by deletePages) - uint pageCount = d->pdfdoc->getNumPages(); - d->pages.resize( pageCount ); - if ( pageCount > 0 ) - { - for ( uint i = 0; i < pageCount ; i++ ) - d->pages[i] = new KPDFPage( i, d->pdfdoc->getPageWidth(i+1), d->pdfdoc->getPageHeight(i+1), d->pdfdoc->getPageRotate(i+1) ); - // filter pages, setup observers and set the first page as current - processPageList( true ); - setCurrentPage( 0 ); - } + // create the generator + // TODO: switch on mimetype for generator selection + generator = new GeneratorPDF(); + documentFileName = docFile; + bool openOk = generator->loadDocument( docFile, pages_vector ); + if ( !openOk ) + return false; // check local directory for an overlay xml // TODO import overlay layers from XML - QString fileName = docFile.contains('/') ? docFile.section('/', -1, -1) : docFile; - fileName = "kpdf/" + QString::number(fileSize) + "." + fileName + ".xml"; - QString localFN = locateLocal( "data", fileName ); - //kdWarning() << localFN << endl; +// QString fileName = docFile.contains('/') ? docFile.section('/', -1, -1) : docFile; +// fileName = "kpdf/" + QString::number(fileSize) + "." + fileName + ".xml"; +// QString localFN = locateLocal( "data", fileName ); +// kdDebug() << "Using '" << localFN << "' as overlay descriptor." << endl; + // filter pages, setup observers and set the first page as current + if ( pages_vector.size() > 0 ) + { + processPageList( true ); + setCurrentPage( 0 ); + } return true; } void KPDFDocument::closeDocument() { - // delete pages and clear container - for ( uint i = 0; i < d->pages.count() ; i++ ) - delete d->pages[i]; - d->pages.clear(); + // delete pages and clear 'pages_vector' container + for ( uint i = 0; i < pages_vector.count() ; i++ ) + delete pages_vector[i]; + pages_vector.clear(); - // broadcast zero pages - processPageList( true ); + // send an empty list to observers (to free their data) + foreachObserver( pageSetup( pages_vector, true ) ); + + // delete contents generator + delete generator; + generator = 0; // reset internal variables d->currentPage = -1; d->searchPage = -1; - - // delete xpds's PDFDoc contents generator - delete d->pdfdoc; - d->pdfdoc = 0; } @@ -318,33 +133,30 @@ void KPDFDocument::addObserver( KPDFDocumentObserver * pObserver ) void KPDFDocument::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 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 != d->paperColor || !d->kpdfOutputDev ) + // reparse generator config and if something changed clear KPDFPages + if ( generator && generator->reparseConfig() ) { - d->paperColor = color; - SplashColor paperColor; - paperColor.rgb8 = splashMakeRGB8( d->paperColor.red(), d->paperColor.green(), d->paperColor.blue() ); - // rebuild the output device using the new paper color - d->docLock.lock(); - delete d->kpdfOutputDev; - d->kpdfOutputDev = new KPDFOutputDev( paperColor ); - if ( d->pdfdoc ) - d->kpdfOutputDev->startDoc( d->pdfdoc->getXRef() ); - d->docLock.unlock(); // invalidate pixmaps and send reload signals to observers - QValueVector::iterator it = d->pages.begin(), end = d->pages.end(); + QValueVector::iterator it = pages_vector.begin(), end = pages_vector.end(); for ( ; it != end; ++it ) - (*it)->deletePixmapsAndLinks(); + (*it)->deletePixmapsAndRects(); foreachObserver( notifyPixmapsCleared() ); } } +const DocumentInfo & KPDFDocument::documentInfo() const +{ + if ( generator ) + return generator->documentInfo(); + return d->noDocumentInfo; +} + +const KPDFPage * KPDFDocument::page( uint n ) const +{ + return ( n < pages_vector.count() ) ? pages_vector[n] : 0; +} + uint KPDFDocument::currentPage() const { return d->currentPage; @@ -352,150 +164,49 @@ uint KPDFDocument::currentPage() const uint KPDFDocument::pages() const { - return d->pdfdoc ? d->pdfdoc->getNumPages() : 0; -} - -QString KPDFDocument::author() const -{ - return d->getDocumentInfo("Author"); -} - -QString KPDFDocument::creationDate() const -{ - return d->getDocumentDate("CreationDate"); -} - -QString KPDFDocument::creator() const -{ - return d->getDocumentInfo("Creator"); -} - -bool KPDFDocument::encrypted() const -{ - if (d->pdfdoc) return d->pdfdoc->isEncrypted(); - else return false; -} - -QString KPDFDocument::keywords() const -{ - return d->getDocumentInfo("Keywords"); -} - -QString KPDFDocument::modificationDate() const -{ - return d->getDocumentDate("ModDate"); -} - -bool KPDFDocument::optimized() const -{ - if (d->pdfdoc) return d->pdfdoc->isLinearized(); - else return false; -} - -float KPDFDocument::PDFversion() const -{ - if (d->pdfdoc) return d->pdfdoc->getPDFVersion(); - else return 0; -} - -QString KPDFDocument::producer() const -{ - return d->getDocumentInfo("Producer"); -} - -QString KPDFDocument::subject() const -{ - return d->getDocumentInfo("Subject"); -} - -QString KPDFDocument::title() const -{ - return d->getDocumentInfo("Title"); + return pages_vector.size(); } bool KPDFDocument::okToPrint() const { - return d->pdfdoc->okToPrint(); + return generator ? generator->allowed( Generator::Print ) : false; } Outline * KPDFDocument::outline() const { - return d->pdfdoc ? d->pdfdoc->getOutline() : 0; -} - -const KPDFPage * KPDFDocument::page( uint n ) const -{ - return ( n < d->pages.count() ) ? d->pages[n] : 0; + return generator ? generator->synopsis().outline : 0; } void KPDFDocument::requestPixmap( int id, uint page, int width, int height, bool syn ) { - KPDFPage * kp = d->pages[page]; - if ( !d->pdfdoc || !kp || kp->width() < 1 || kp->height() < 1 ) + KPDFPage * kp = pages_vector[ page ]; + if ( !generator || !kp || kp->width() < 1 || kp->height() < 1 ) return; - //kdDebug() << "id: " << id << " is requesting pixmap for page " << page << " [" << width << " x " << height << "]." << endl; - if ( syn ) - { - // in-place Pixmap generation for syncronous requests - if ( !kp->hasPixmap( id, width, height ) ) - { - // compute dpi used to get an image with desired width and height - double fakeDpiX = width * 72.0 / kp->width(), - fakeDpiY = height * 72.0 / kp->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 = !kp->hasSearchPage() && (width == kp->width()) && (height == kp->height()); - // generate links and activeRects if rendering pages on pageview - bool genLinks = id == PAGEVIEW_ID; - d->kpdfOutputDev->setParams( width, height, genTextPage, genLinks, genLinks ); - - d->docLock.lock(); - d->pdfdoc->displayPage( d->kpdfOutputDev, page + 1, fakeDpiX, fakeDpiY, 0, true, genLinks ); - d->docLock.unlock(); - - kp->setPixmap( id, d->kpdfOutputDev->takePixmap() ); - if ( genTextPage ) - kp->setSearchPage( d->kpdfOutputDev->takeTextPage() ); - if ( genLinks ) - { - kp->setLinks( d->kpdfOutputDev->takeLinks() ); - kp->setActiveRects( d->kpdfOutputDev->takeActiveRects() ); - } - - d->observers[id]->notifyPixmapChanged( page ); - } - } - else - { - //TODO asyncronous events queuing - } + bool pixChanged = generator->requestPixmap( id, kp, width, height, syn ); + if ( pixChanged ) + d->observers[id]->notifyPixmapChanged( page ); } -void KPDFDocument::requestTextPage( uint n ) +void KPDFDocument::requestTextPage( uint page ) { - KPDFPage * page = d->pages[ n ]; - // build a TextPage using the lightweight KPDFTextDev generator.. - KPDFTextDev td; - d->docLock.lock(); - d->pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, true, false ); - d->docLock.unlock(); - // ..and attach it to the page - page->setSearchPage( td.takeTextPage() ); + KPDFPage * kp = pages_vector[ page ]; + if ( !generator || !kp ) + return; + + generator->requestTextPage( kp ); } void KPDFDocument::setCurrentPage( int page, const QRect & viewport ) { if ( page < 0 ) page = 0; - else if ( page > (int)d->pages.count() ) - page = d->pages.count() - 1; - if ( page == d->currentPage && viewport == d->currentViewport ) + else if ( page > (int)pages_vector.count() ) + page = pages_vector.count() - 1; + if ( page == d->currentPage ) return; d->currentPage = page; - d->currentViewport = viewport; foreachObserver( pageSetCurrent( page, viewport ) ); } @@ -514,9 +225,9 @@ void KPDFDocument::findText( const QString & string, bool keepCase ) // continue checking last SearchPage first (if it is the current page) int currentPage = d->currentPage; - int pageCount = d->pages.count(); + int pageCount = pages_vector.count(); KPDFPage * foundPage = 0, - * lastPage = (d->searchPage > -1) ? d->pages[ d->searchPage ] : 0; + * lastPage = (d->searchPage > -1) ? pages_vector[ d->searchPage ] : 0; if ( lastPage && d->searchPage == currentPage ) if ( lastPage->hasText( d->searchText, d->searchCase, false ) ) foundPage = lastPage; @@ -538,7 +249,7 @@ void KPDFDocument::findText( const QString & string, bool keepCase ) else break; } - KPDFPage * page = d->pages[ currentPage ]; + KPDFPage * page = pages_vector[ currentPage ]; if ( !page->hasSearchPage() ) requestTextPage( page->number() ); if ( page->hasText( d->searchText, d->searchCase, true ) ) @@ -570,7 +281,7 @@ void KPDFDocument::findTextAll( const QString & pattern, bool keepCase ) void KPDFDocument::toggleBookmark( int n ) { - KPDFPage * page = ( n < (int)d->pages.count() ) ? d->pages[ n ] : 0; + KPDFPage * page = ( n < (int)pages_vector.count() ) ? pages_vector[ n ] : 0; if ( page ) { page->toggleAttribute( KPDFPage::Bookmark ); @@ -583,209 +294,132 @@ void KPDFDocument::processLink( const KPDFLink * link ) if ( !link ) return; - switch( link->type() ) + switch( link->linkType() ) { - case KPDFLink::Goto: { - // make copies of the 'nameDest' (string) and the 'dest' (class) - char * namedDest = 0; - link->copyString( namedDest, link->getNamedDest() ); - LinkDest * dest = link->getDest() ? ((LinkDest*)link->getDest())->copy() : 0; + case KPDFLink::Goto: { + const KPDFLinkGoto * go = static_cast< const KPDFLinkGoto * >( link ); + KPDFLinkGoto::Viewport destVp = go->destViewport(); - // first open filename if link is pointing outside this document - QString fileName( link->getFileName() ); - if ( !fileName.isNull() ) - if ( !openRelativeFile( fileName ) ) + // first open filename if link is pointing outside this document + if ( go->isExternal() && !openRelativeFile( go->fileName() ) ) { - kdWarning() << "Link: Error opening '" << fileName << "'." << endl; - delete dest; - delete namedDest; + kdWarning() << "Link: Error opening '" << go->fileName() << "'." << endl; return; } - // now previous KPDFLink and KPDFPage don't exist anymore! - if ( namedDest && !dest ) - { - GString temp( namedDest ); - d->docLock.lock(); - dest = d->pdfdoc->findDest( &temp ); - d->docLock.unlock(); - } - if ( dest && dest->isOk() ) - { - // get destination page number - int pageNum = dest->getPageNum() - 1; - if ( dest->isPageRef() ) + // note: if external file is opened, 'link' doesn't exist anymore! + setCurrentPage( destVp.page ); //TODO implement and use viewport + } break; + + case KPDFLink::Execute: { + const KPDFLinkExecute * exe = static_cast< const KPDFLinkExecute * >( link ); + QString fileName = exe->fileName(); + if ( fileName.endsWith( ".pdf" ) || fileName.endsWith( ".PDF" ) ) { - Ref ref = dest->getPageRef(); - d->docLock.lock(); - pageNum = d->pdfdoc->findPage( ref.num, ref.gen ) - 1; - d->docLock.unlock(); + openRelativeFile( fileName ); + return; } - // get destination position - QRect r; - //KPDFPage * page = (pageNum >= 0 && pageNum < (int)d->pages.count()) ? d->pages[ pageNum ] : 0; - //if ( page ) - /* TODO - switch ( dest->getKind() ) + + // Albert: the only pdf i have that has that kind of link don't define + // an application and use the fileName as the file to open + fileName = giveAbsolutePath( fileName ); + KMimeType::Ptr mime = KMimeType::findByPath( fileName ); + // Check executables + if ( KRun::isExecutableFile( fileName, mime->name() ) ) { - 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 - case destFit - case destFitB - fit page - case destFitH - case destFitBH - read top, fit Width - case destFitV - case destFitBV - read left, fit Height - destFitR - read and fit left,bottom,right,top - }*/ - setCurrentPage( pageNum, r ); - } - delete namedDest; - delete dest; - } break; + // Don't have any pdf that uses this code path, just a guess on how it should work + if ( !exe->parameters().isEmpty() ) + { + fileName = giveAbsolutePath( exe->parameters() ); + mime = KMimeType::findByPath( fileName ); + if ( KRun::isExecutableFile( fileName, mime->name() ) ) + { + // this case is a link pointing to an executable with a parameter + // that also is an executable, possibly a hand-crafted pdf + KMessageBox::information( 0, i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") ); + return; + } + } + else + { + // this case is a link pointing to an executable with no parameters + // core developers find unacceptable executing it even after asking the user + KMessageBox::information( 0, i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") ); + return; + } + } - case KPDFLink::Execute: { - QString fileName( link->getFileName() ); - if ( fileName.endsWith( ".pdf" ) || fileName.endsWith( ".PDF" ) ) - openRelativeFile( fileName ); - else - { - KMimeType::Ptr mime; - KService::Ptr ptr; + KService::Ptr ptr = KServiceTypeProfile::preferredService( mime->name(), "Application" ); + if ( ptr ) + { + KURL::List lst; + lst.append( fileName ); + KRun::run( *ptr, lst ); + } + else + KMessageBox::information( 0, i18n( "No application found for opening file of mimetype %1." ).arg( mime->name() ) ); + } break; - // the only pdf i have that has that kind of link don't define an application - // and use the fileName as the file to open + case KPDFLink::Action: { + const KPDFLinkAction * action = static_cast< const KPDFLinkAction * >( link ); + switch( action->actionType() ) + { + case KPDFLinkAction::PageFirst: + setCurrentPage( 0 ); + break; + case KPDFLinkAction::PagePrev: + if ( d->currentPage > 0 ) + setCurrentPage( d->currentPage - 1 ); + break; + case KPDFLinkAction::PageNext: + if ( d->currentPage < (int)pages_vector.count() - 1 ) + setCurrentPage( d->currentPage + 1 ); + break; + case KPDFLinkAction::PageLast: + setCurrentPage( pages_vector.count() - 1 ); + break; + case KPDFLinkAction::HistoryBack: + {} //TODO + break; + case KPDFLinkAction::HistoryForward: + {} //TODO + break; + case KPDFLinkAction::Quit: + kapp->quit(); + break; + } + } break; - fileName = giveAbsolutePath( fileName ); - mime = KMimeType::findByPath( fileName ); - // Check executables - if ( KRun::isExecutableFile( fileName, mime->name() ) ) - { - // Don't have any pdf that uses this code path, just a guess on how it should work - if ( link->getParameters() ) - { - fileName = giveAbsolutePath( link->getParameters() ); - mime = KMimeType::findByPath( fileName ); - if ( KRun::isExecutableFile( fileName, mime->name() ) ) - { - // this case is a link pointing to an executable with a parameter - // that also is an executable, possibly a hand-crafted pdf - KMessageBox::information( 0, i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") ); - return; - } - } - else - { - // this case is a link pointing to an executable with no parameters - // core developers find unacceptable executing it even after asking the user - KMessageBox::information( 0, i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") ); - return; - } - } + case KPDFLink::Browse: { + const KPDFLinkBrowse * browse = static_cast< const KPDFLinkBrowse * >( link ); + // get service for web browsing + KService::Ptr ptr = KServiceTypeProfile::preferredService("text/html", "Application"); + KURL::List lst; + // append 'url' parameter to the service and run it + lst.append( browse->url() ); + KRun::run( *ptr, lst ); + } break; - ptr = KServiceTypeProfile::preferredService(mime->name(), "Application"); - if (ptr) - { - KURL::List lst; - lst.append( fileName ); - KRun::run( *ptr, lst ); - } - else KMessageBox::information( 0, i18n("No application found for opening file of mimetype %1.").arg(mime->name()) ); - } - } break; - - case KPDFLink::Named: { - const char * name = link->getName(); - if ( !strcmp( name, "NextPage" ) && (d->currentPage < (int)d->pages.count() - 1) ) - setCurrentPage( d->currentPage + 1 ); - else if ( !strcmp( name, "PrevPage" ) && d->currentPage > 0 ) - setCurrentPage( d->currentPage - 1 ); - else if ( !strcmp( name, "FirstPage" ) ) - setCurrentPage( 0 ); - else if ( !strcmp( name, "LastPage" ) ) - setCurrentPage( d->pages.count() - 1 ); - else if ( !strcmp( name, "GoBack" ) ) - {} //TODO - else if ( !strcmp( name, "GoForward" ) ) - {} //TODO - else if ( !strcmp( name, "Quit" ) ) - kapp->quit(); - else - {}//FIXME error(-1, "Unknown named action: '%s'", name); - } break; - - case KPDFLink::URI: { - KService::Ptr ptr = KServiceTypeProfile::preferredService("text/html", "Application"); - KURL::List lst; - lst.append( link->getURI() ); - KRun::run( *ptr, lst ); - } break; - - case KPDFLink::Movie: - case KPDFLink::Unknown: - // unimplemented cases - break; + case KPDFLink::Movie: + // TODO this + break; } } -bool KPDFDocument::print(KPrinter &printer) +bool KPDFDocument::print( KPrinter &printer ) { - KTempFile tf( QString::null, ".ps" ); - PSOutputDev *psOut = new PSOutputDev(tf.name().latin1(), d->pdfdoc->getXRef(), d->pdfdoc->getCatalog(), 1, d->pdfdoc->getNumPages(), psModePS); - - if (psOut->isOk()) - { - std::list pages; - - if (!printer.previewOnly()) - { - QValueList pageList = printer.pageList(); - QValueList::const_iterator it; - - for(it = pageList.begin(); it != pageList.end(); ++it) pages.push_back(*it); - } - else - { - for(int i = 1; i <= d->pdfdoc->getNumPages(); i++) pages.push_back(i); - } - - d->docLock.lock(); - d->pdfdoc->displayPages(psOut, pages, 72, 72, 0, globalParams->getPSCrop(), gFalse); - d->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; - } + return generator ? generator->print( printer ) : false; } -//END slots + QString KPDFDocument::giveAbsolutePath( const QString & fileName ) { - const char * currentName = d->pdfdoc->getFileName()->getCString(); - if ( !currentName || currentName[0] == 0 ) - return QString::null; + if ( documentFileName.isEmpty() ) + return QString::null; // convert the pdf fileName to absolute using current pdf path - QFileInfo currentInfo( currentName ); - return currentInfo.dir().absFilePath( fileName ); + QFileInfo currentInfo( documentFileName ); + return currentInfo.dir().absFilePath( fileName ); } bool KPDFDocument::openRelativeFile( const QString & fileName ) @@ -806,23 +440,15 @@ void KPDFDocument::processPageList( bool documentChanged ) unHilightPages(); else { - uint pageCount = d->pages.count(); + uint pageCount = pages_vector.count(); for ( uint i = 0; i < pageCount ; i++ ) { - KPDFPage * page = d->pages[ i ]; + KPDFPage * page = pages_vector[ i ]; page->clearAttribute( KPDFPage::Highlight ); if ( d->filterText.length() > 2 ) { if ( !page->hasSearchPage() ) - { - // build a TextPage using the lightweight KPDFTextDev generator.. - KPDFTextDev td; - d->docLock.lock(); - d->pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, true, false ); - d->docLock.unlock(); - // ..and attach it to the page - page->setSearchPage( td.takeTextPage() ); - } + requestTextPage( i ); if ( page->hasText( d->filterText, d->filterCase, true ) ) page->setAttribute( KPDFPage::Highlight ); } @@ -830,7 +456,7 @@ void KPDFDocument::processPageList( bool documentChanged ) } // send the list to observers - foreachObserver( pageSetup( d->pages, documentChanged ) ); + foreachObserver( pageSetup( pages_vector, documentChanged ) ); } void KPDFDocument::unHilightPages() @@ -839,7 +465,7 @@ void KPDFDocument::unHilightPages() return; d->filterText = QString::null; - QValueVector::iterator it = d->pages.begin(), end = d->pages.end(); + QValueVector::iterator it = pages_vector.begin(), end = pages_vector.end(); for ( ; it != end; ++it ) { KPDFPage * page = *it; @@ -850,79 +476,3 @@ void KPDFDocument::unHilightPages() } } } - -/** 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; -} -*/ diff --git a/kpdf/document.h b/kpdf/document.h index 738131840..52de635cf 100644 --- a/kpdf/document.h +++ b/kpdf/document.h @@ -12,11 +12,14 @@ #define _KPDF_DOCUMENT_H_ #include +#include 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 diff --git a/kpdf/generator.h b/kpdf/generator.h new file mode 100644 index 000000000..f82698558 --- /dev/null +++ b/kpdf/generator.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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 +#include +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 diff --git a/kpdf/generator_pdf.cpp b/kpdf/generator_pdf.cpp new file mode 100644 index 000000000..186e8b833 --- /dev/null +++ b/kpdf/generator_pdf.cpp @@ -0,0 +1,548 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * Copyright (C) 2004 by Enrico Ros * + * * + * 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 +#include +#include +#include +#include +#include +#include + +// 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 & 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 pages; + + if (!printer.previewOnly()) + { + QValueList pageList = printer.pageList(); + QValueList::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 +#include +#include + +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; +} +*/ diff --git a/kpdf/generator_pdf.h b/kpdf/generator_pdf.h new file mode 100644 index 000000000..df75a06ae --- /dev/null +++ b/kpdf/generator_pdf.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2004 by Albert Astals Cid * + * Copyright (C) 2004 by Enrico Ros * + * * + * 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 +#include +#include +#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 & 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 + +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 diff --git a/kpdf/kpdf_error.cpp b/kpdf/kpdf_error.cpp index ca96472ce..00939fe18 100644 --- a/kpdf/kpdf_error.cpp +++ b/kpdf/kpdf_error.cpp @@ -15,8 +15,8 @@ #include #include #include -#include "GlobalParams.h" -#include "Error.h" +#include "xpdf/GlobalParams.h" +#include "xpdf/Error.h" #include diff --git a/kpdf/kpdf_part.cpp b/kpdf/kpdf_part.cpp index 363cfd3e1..31f81d58c 100644 --- a/kpdf/kpdf_part.cpp +++ b/kpdf/kpdf_part.cpp @@ -48,7 +48,7 @@ #include #include -#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() diff --git a/kpdf/kpdf_part.h b/kpdf/kpdf_part.h index 72d18c5a5..f13510c5f 100644 --- a/kpdf/kpdf_part.h +++ b/kpdf/kpdf_part.h @@ -35,9 +35,6 @@ class KSelectAction; class KAboutData; class KPrinter; -class LinkAction; -class LinkDest; - class ThumbnailList; class PageView; class SearchWidget; diff --git a/kpdf/thumbnailgenerator.h b/kpdf/link.cpp similarity index 54% rename from kpdf/thumbnailgenerator.h rename to kpdf/link.cpp index ea2092a0c..f62b3531b 100644 --- a/kpdf/thumbnailgenerator.h +++ b/kpdf/link.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2004 by Albert Astals Cid * + * Copyright (C) 2004 by Enrico Ros * * * * 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 - -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 ); + } +} +*/ diff --git a/kpdf/link.h b/kpdf/link.h new file mode 100644 index 000000000..bc3fe23a9 --- /dev/null +++ b/kpdf/link.h @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (C) 2004 by Enrico Ros * + * * + * 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 +#include + +/** + * @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 diff --git a/kpdf/page.cpp b/kpdf/page.cpp index d08d7eb3a..755e1ec36 100644 --- a/kpdf/page.cpp +++ b/kpdf/page.cpp @@ -15,17 +15,20 @@ #include #include #include +#include // system includes #include // 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 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 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::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( 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 ); -} diff --git a/kpdf/page.h b/kpdf/page.h index 49dd86107..292f92559 100644 --- a/kpdf/page.h +++ b/kpdf/page.h @@ -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 links ); - void setActiveRects( const QValueList 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 diff --git a/kpdf/pageview.cpp b/kpdf/pageview.cpp index edb07a892..4792a5ef6 100644 --- a/kpdf/pageview.cpp +++ b/kpdf/pageview.cpp @@ -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 & 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() ); } diff --git a/kpdf/properties.ui b/kpdf/properties.ui index 03d00861e..d9d9593cb 100644 --- a/kpdf/properties.ui +++ b/kpdf/properties.ui @@ -21,7 +21,7 @@ textLabel1_3_2_3_6 - PDF version: + Format: @@ -50,6 +50,12 @@ Expanding + + + 20 + 20 + + @@ -61,6 +67,12 @@ Expanding + + + 20 + 20 + + diff --git a/kpdf/propertiesdialog.cpp b/kpdf/propertiesdialog.cpp index 6d6c09432..b218fbe4c 100644 --- a/kpdf/propertiesdialog.cpp +++ b/kpdf/propertiesdialog.cpp @@ -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 ); } diff --git a/kpdf/thumbnailgenerator.cpp b/kpdf/thumbnailgenerator.cpp deleted file mode 100644 index 45098b5bd..000000000 --- a/kpdf/thumbnailgenerator.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2004 by Albert Astals Cid * - * * - * 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 -#include -#include -#include - -#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); -} diff --git a/kpdf/toc.cpp b/kpdf/toc.cpp index 2d1d7306d..ac1d2b5d4 100644 --- a/kpdf/toc.cpp +++ b/kpdf/toc.cpp @@ -139,8 +139,9 @@ QString TOC::getTitle(Unicode *u, int length, UnicodeMap *uMap) const void TOC::slotExecuted(QListViewItem *i) { TOCItem *ti = dynamic_cast(i); - KPDFLink l( ti->getAction() ); - m_document->processLink( &l ); + //FIXME + //KPDFLink l( ti->getAction() ); + //m_document->processLink( &l ); } #include "toc.moc"