diff --git a/kpdf/Makefile.am b/kpdf/Makefile.am index 537d9cd54..9b4e7e3a0 100644 --- a/kpdf/Makefile.am +++ b/kpdf/Makefile.am @@ -1,52 +1,52 @@ # set the include path for X, qt and KDE INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../splash -I$(srcdir)/../goo -I$(srcdir)/../xpdf $(all_includes) $(FREETYPE_CFLAGS) # let automoc handle all of the meta source files (moc) METASOURCES = AUTO messages: rc.cpp $(XGETTEXT) *.cpp -o $(podir)/kpdf.pot # TODO: fix the code! KDE_OPTIONS = nofinal KDE_ICON = kpdf # this Makefile creates both a KPart application and a KPart ######################################################################### # APPLICATION SECTION ######################################################################### # this is the program that gets installed. it's name is used for all # of the other Makefile.am variables bin_PROGRAMS = kpdf # the application source, library search path, and link libraries kpdf_SOURCES = main.cpp kpdf_shell.cpp kpdf_LDFLAGS = $(KDE_RPATH) $(all_libraries) kpdf_LDADD = $(LIB_KPARTS) EXTRA_DIST = kpdf.desktop xdg_apps_DATA = kpdf.desktop # this is where the shell's XML-GUI resource file goes shellrcdir = $(kde_datadir)/kpdf shellrc_DATA = kpdf_shell.rc ######################################################################### # KPART SECTION ######################################################################### kde_module_LTLIBRARIES = libkpdfpart.la # the Part's source, library search path, and link libraries -libkpdfpart_la_SOURCES = QOutputDev.cpp QOutputDevKPrinter.cpp kpdf_part.cpp kpdf_pagewidget.cc thumbnail.cpp thumbnaillist.cpp kpdf_error.cpp xpdf_errors.cpp thumbnailgenerator.cpp +libkpdfpart_la_SOURCES = QOutputDev.cpp QOutputDevKPrinter.cpp kpdf_part.cpp kpdf_pagewidget.cc thumbnail.cpp thumbnaillist.cpp kpdf_error.cpp xpdf_errors.cpp thumbnailgenerator.cpp document.cpp page.cpp libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) libkpdfpart_la_LIBADD = ../xpdf/libxpdf.la $(LIB_KPARTS) $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm # this is where the desktop file will go partdesktopdir = $(kde_servicesdir) partdesktop_DATA = kpdf_part.desktop # this is where the part's XML-GUI resource file goes partrcdir = $(kde_datadir)/kpdfpart partrc_DATA = kpdf_part.rc diff --git a/kpdf/document.cpp b/kpdf/document.cpp new file mode 100644 index 000000000..5dc649b40 --- /dev/null +++ b/kpdf/document.cpp @@ -0,0 +1,236 @@ +/*************************************************************************** + * 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 includes +#include +#include +#include + +// local includes +#include "PDFDoc.h" +//#include "TextOutputDev.h" + +#include "kpdf_error.h" +#include "document.h" +#include "page.h" + +// structure used internally by KPDFDocument for data storage +struct KPDFDocumentPrivate +{ + // document related + QMutex docLock; + PDFDoc * pdfdoc; + int currentPage; + QValueVector< KPDFPage* > pages; + + // observers related (note: won't delete oservers) + QValueList< KPDFDocumentObserver* > observers; +}; + +#define foreachObserver( cmd ) {\ + QValueList::iterator it = d->observers.begin();\ + QValueList::iterator end = d->observers.end();\ + for ( ; it != end ; ++ it ) { (*it)-> cmd ; } } + +/* + * KPDFDocument class + */ +KPDFDocument::KPDFDocument() +{ + d = new KPDFDocumentPrivate; + d->pdfdoc = 0; +} + +KPDFDocument::~KPDFDocument() +{ + close(); + delete d; +} + +bool KPDFDocument::openFile( const QString & docFile ) +{ + // docFile is always local so we can use QFile on it + QFile fileReadTest( docFile ); + if ( !fileReadTest.open( IO_ReadOnly ) ) + return false; + fileReadTest.close(); + + GString *filename = new GString( QFile::encodeName( docFile ) ); + delete d->pdfdoc; + d->pdfdoc = new PDFDoc( filename, 0, 0 ); + deletePages(); + + if ( !d->pdfdoc->isOk() || d->pdfdoc->getNumPages() < 1 ) + { + delete d->pdfdoc; + d->pdfdoc = 0; + return false; + } + + // clear xpdf errors + errors::clear(); + + // build Pages + uint pageCount = d->pdfdoc->getNumPages(); + d->pages.resize( pageCount ); + for ( uint i = 0; i < pageCount ; i++ ) + d->pages[i] = new KPDFPage( i, d->pdfdoc->getPageHeight(i + 1), d->pdfdoc->getPageWidth(i + 1) ); + + //filter = NONE; TODO + sendFilteredPageList(); + + setCurrentPage( 0 ); + + return true; +} + +void KPDFDocument::close() +{ + //stopRunningJobs()... + deletePages(); + delete d->pdfdoc; + d->pdfdoc = 0; +} + +const KPDFPage * KPDFDocument::page( uint n ) const +{ + return ( n < d->pages.count() ) ? d->pages[n] : 0; +} + +uint KPDFDocument::pages() const +{ + return d->pdfdoc ? d->pdfdoc->getNumPages() : 0; +} + +void KPDFDocument::setCurrentPage( uint page, float position ) +{ //FIXME event queuing to avoid flow interruption (!!??) + if ( (int)page == d->currentPage ) //TODO check position + return; + d->currentPage = page; + foreachObserver( pageSetCurrent( page, position ) ); + pageChanged(); +} + +void KPDFDocument::find( bool /*nextMatch*/, const QString & /*text*/ ) +{ +/* + TextOutputDev *textOut; + Unicode *u; + bool found; + double xMin1, yMin1, xMax1, yMax1; + int len, pg; + + // This is more or less copied from what xpdf does, surely can be optimized + len = s.length(); + u = (Unicode *)gmalloc(len * sizeof(Unicode)); + for (int i = 0; i < len; ++i) u[i] = (Unicode)(s.latin1()[i] & 0xff); + + // search current + found = m_outputDev->find(u, len, next); + + if (!found) + { + // search following pages + textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse); + if (!textOut->isOk()) + { + gfree(u); + delete textOut; + return; + } + + pg = m_currentPage + 1; + while(!found && pg <= d->pdfdoc->getNumPages()) + { + m_docMutex.lock(); + d->pdfdoc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse); + m_docMutex.unlock(); + found = textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, &xMin1, &yMin1, &xMax1, &yMax1); + if (!found) pg++; + } + + if (!found && m_currentPage != 1) + { + if (KMessageBox::questionYesNo(widget(), i18n("End of document reached.\nContinue from the beginning?")) == KMessageBox::Yes) + { + // search previous pages + pg = 1; + while(!found && pg < m_currentPage) + { + m_docMutex.lock(); + d->pdfdoc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse); + m_docMutex.unlock(); + found = textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, &xMin1, &yMin1, &xMax1, &yMax1); + if (!found) pg++; + } + } + } + + delete textOut; + if (found) + { + kdDebug() << "found at " << pg << endl; + goToPage(pg); + // xpdf says: can happen that we do not find the text if coalescing is bad OUCH + m_outputDev->find(u, len, false); + } + else + { + if (next) KMessageBox::information(widget(), i18n("No more matches found for '%1'.").arg(s)); + else KMessageBox::information(widget(), i18n("No matches found for '%1'.").arg(s)); + } + } + + if (found) m_findText = s; + else m_findText = QString::null; + + gfree(u); +*/ +} + +void KPDFDocument::goToLink( /* QString anchor */ ) +{ + +} + +void KPDFDocument::addObserver( KPDFDocumentObserver * pObserver ) +{ + d->observers.push_back( pObserver ); +} + +void KPDFDocument::sendFilteredPageList() +{ //TODO implement filtering + + // make up a value list of the pages [1,2,3..] + uint pageCount = d->pages.count(); + QValueList pagesList; + for ( uint i = 0; i < pageCount ; i++ ) + pagesList.push_back( i ); + + // send the list to observers + foreachObserver( pageSetup( pagesList ) ); +} + +void KPDFDocument::deletePages() +{ + if ( d->pages.isEmpty() ) + return; + + // broadcast an empty page list to observers + QValueList pagesList; + foreachObserver( pageSetup( pagesList ) ); + + // delete pages and clear container + for ( uint i = 0; i < d->pages.count() ; i++ ) + delete d->pages[i]; + d->pages.clear(); + d->currentPage = -1; +} + +#include "document.moc" diff --git a/kpdf/document.h b/kpdf/document.h new file mode 100644 index 000000000..2af3232f2 --- /dev/null +++ b/kpdf/document.h @@ -0,0 +1,84 @@ +/*************************************************************************** + * 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_DOCUMENT_H_ +#define _KPDF_DOCUMENT_H_ + +#include +#include + +class KPDFPage; + +/** + * @short Base class for objects being notified when something changes. + * + * Inherit this class and call KPDFDocument->addObserver( obsClass ) to get + * notified of asyncronous events (a new thumbnail has arrived, a pixmap has + * changed, and other events). + */ +class KPDFDocumentObserver +{ +public: + // monitor changes in pixmaps (generation thread complete) + virtual void notifyThumbnailChanged( int /*pageNumber*/ ) {}; + virtual void notifyPixmapChanged( int /*pageNumber*/ ) {}; + + // commands from the Document to observers + virtual void pageSetup( const QValueList & /*pages*/ ) {}; + virtual void pageSetCurrent( int /*pageNumber*/, float /*position*/ ) {}; + virtual void pageSetHilight( int /*x*/, int /*y*/, int /*width*/, int /*height*/ ) {}; +}; + + +/** + * @short The information container. Actions (like find) take place here. + * + * xxxxxx + * yyy. + */ +class KPDFDocument : public QObject +{ + Q_OBJECT + +public: + KPDFDocument(); + ~KPDFDocument(); + + // observers related methods + void addObserver( KPDFDocumentObserver * pObserver ); + + // document handling + bool openFile( const QString & docFile ); + void close(); + + // document control + const KPDFPage * page( uint page ) const; + uint pages() const; + uint currentPage() const { return 0; } + void setCurrentPage( uint page, float position = 0.0 ); + void find( bool nextMatch, const QString & text = "" ); + void goToLink( /* QString anchor */ ); + bool atBegin() {return false;} + bool atEnd() {return false;} + + void setZoom( float zoom ) {}; + void zoom( float offset ) {}; + +signals: + void pageChanged(); + +private: + void sendFilteredPageList(); + void deletePages(); + + class KPDFDocumentPrivate * d; +}; + + +#endif diff --git a/kpdf/kpdf_pagewidget.cc b/kpdf/kpdf_pagewidget.cc index d9dbaa628..8273414bf 100644 --- a/kpdf/kpdf_pagewidget.cc +++ b/kpdf/kpdf_pagewidget.cc @@ -1,402 +1,401 @@ /*************************************************************************** * Copyright (C) 2002 by Wilco Greven * * Copyright (C) 2003 by Christophe Devriese * * * * Copyright (C) 2003 by Laurent Montel * * Copyright (C) 2003 by Dirk Mueller * * Copyright (C) 2004 by Albert Astals Cid * * Copyright (C) 2004 by James Ots * * * * 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 #include "PDFDoc.h" #include "kpdf_pagewidget.h" #include "kpdf_pagewidget.moc" #include "QOutputDev.h" #include #include namespace KPDF { PageWidget::PageWidget(QWidget* parent, const char* name, QMutex *docMutex) : QScrollView(parent, name, WRepaintNoErase), m_doc(0), m_docMutex(docMutex), m_zoomFactor( 1.0 ), m_currentPage( 1 ), m_pressedAction( 0 ), m_selection( false ) { SplashColor paperColor; paperColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff); m_outputdev = new QOutputDev(paperColor); setFocusPolicy( QWidget::StrongFocus ); + setAcceptDrops( true ); viewport()->setFocusPolicy( QWidget::WheelFocus ); - QPushButton * w = new QPushButton( viewport() ); - w->setPixmap( SmallIcon("up") ); - setCornerWidget( w ); + QPushButton * w = new QPushButton( viewport() ); + w->setPixmap( SmallIcon("up") ); + setCornerWidget( w ); } PageWidget::~PageWidget() { delete m_outputdev; } void PageWidget::setPDFDocument(PDFDoc* doc) { m_doc = doc; m_outputdev -> startDoc(doc->getXRef()); m_currentPage = 1; updatePixmap(); } void PageWidget::setPixelsPerPoint(float ppp) { m_ppp = ppp; } void PageWidget::contentsMousePressEvent(QMouseEvent* e) { if (m_doc == 0) return; if ( e->button() & LeftButton ) { m_dragGrabPos = e -> globalPos(); setCursor( sizeAllCursor ); } else if ( e->button() & RightButton ) { emit rightClick(); } m_pressedAction = m_doc->findLink(e->x()/m_ppp, e->y()/m_ppp); } void PageWidget::contentsMouseReleaseEvent(QMouseEvent* e) { if (m_doc == 0) return; if ( e -> button() & LeftButton ) { setCursor( arrowCursor ); } else { LinkAction* action = m_doc->findLink(e->x()/m_ppp, e->y()/m_ppp); if (action == m_pressedAction) emit linkClicked(action); m_pressedAction = 0; } } void PageWidget::contentsMouseMoveEvent(QMouseEvent* e) { if (m_doc == 0) return; if ( e->state() & LeftButton ) { QPoint delta = m_dragGrabPos - e->globalPos(); scrollBy( delta.x(), delta.y() ); m_dragGrabPos = e->globalPos(); } else { LinkAction* action = m_doc->findLink(e->x()/m_ppp, e->y()/m_ppp); setCursor(action != 0 ? Qt::PointingHandCursor : Qt::ArrowCursor); } } void PageWidget::drawContents ( QPainter *p, int clipx, int clipy, int clipw, int cliph ) { QImage im; QColor bc(KGlobalSettings::calculateAlternateBackgroundColor(KGlobalSettings::baseColor())); if (m_outputdev) im = m_outputdev->getImage(); if ( !im.isNull() ) { p->drawImage ( clipx, clipy, im, clipx, clipy, clipw, cliph ); if ((clipw + clipx) > im.width()) p->fillRect ( im.width(), clipy, clipw - (im.width() - clipx), im.height() - clipy, bc ); if ((cliph + clipy) > im.height()) p->fillRect ( clipx, im.height(), clipw, cliph - (im.height() - clipy), bc ); if (m_selection) { p->setBrush(Qt::SolidPattern); p->setPen(QPen(Qt::black, 1)); // should not be necessary bug a Qt bug makes it necessary p->setRasterOp(Qt::NotROP); p->drawRect(qRound(m_xMin*m_zoomFactor), qRound(m_yMin*m_zoomFactor), qRound((m_xMax- m_xMin)*m_zoomFactor), qRound((m_yMax- m_yMin)*m_zoomFactor)); } } else p->fillRect ( clipx, clipy, clipw, cliph, bc ); } void PageWidget::zoomTo( double _value ) { if ( m_zoomFactor != _value) { m_zoomFactor = _value; updatePixmap(); } } void PageWidget::zoomIn() { m_zoomFactor += 0.1; updatePixmap(); } void PageWidget::zoomOut() { if ( (m_zoomFactor-0.1)<0.1 ) return; m_zoomFactor -= 0.1; updatePixmap(); } void PageWidget::setPage(int page) { // any idea why this mutex is necessary? static QMutex mutex; m_selection = false; Q_ASSERT(mutex.locked() == false); mutex.lock(); if (m_doc) { m_currentPage = page; } else { m_currentPage = 0; } updatePixmap(); mutex.unlock(); } void PageWidget::enableScrollBars( bool b ) { setHScrollBarMode( b ? Auto : AlwaysOff ); setVScrollBarMode( b ? Auto : AlwaysOff ); } void PageWidget::scrollRight() { horizontalScrollBar()->addLine(); } void PageWidget::scrollLeft() { horizontalScrollBar()->subtractLine(); } void PageWidget::scrollDown() { verticalScrollBar()->addLine(); } void PageWidget::scrollUp() { verticalScrollBar()->subtractLine(); } void PageWidget::scrollBottom() { verticalScrollBar()->setValue( verticalScrollBar()->maxValue() ); } void PageWidget::scrollTop() { verticalScrollBar()->setValue( verticalScrollBar()->minValue() ); } void PageWidget::keyPressEvent( QKeyEvent* e ) { switch ( e->key() ) { case Key_Up: if ( atTop() ) emit ReadUp(); else scrollUp(); break; case Key_Down: if ( atBottom() ) emit ReadDown(); else scrollDown(); break; case Key_Left: scrollLeft(); break; case Key_Right: scrollRight(); break; case Key_Space: { if( e->state() != ShiftButton ) { emit spacePressed(); } } default: e->ignore(); return; } e->accept(); } bool PageWidget::atTop() const { return verticalScrollBar()->value() == verticalScrollBar()->minValue(); } bool PageWidget::atBottom() const { return verticalScrollBar()->value() == verticalScrollBar()->maxValue(); } void PageWidget::wheelEvent( QWheelEvent *e ) { int delta = e->delta(); e->accept(); if ((e->state() & ControlButton) == ControlButton) { if ( e->delta() > 0 ) emit ZoomOut(); else emit ZoomIn(); } else if ( delta <= -120 && atBottom() ) { emit ReadDown(); } else if ( delta >= 120 && atTop()) { emit ReadUp(); } else QScrollView::wheelEvent( e ); } void PageWidget::updatePixmap() { if ( m_doc ) { // Pixels per point when the zoomFactor is 1. - const float basePpp = QPaintDevice::x11AppDpiX() / 72.0; - - const float ppp = basePpp * m_zoomFactor; // pixels per point + const float ppp = (float)QPaintDevice::x11AppDpiX() * m_zoomFactor; // pixels per point m_docMutex->lock(); - m_doc->displayPage(m_outputdev, m_currentPage, ppp * 72.0, ppp * 72.0, 0, true, true); + m_doc->displayPage(m_outputdev, m_currentPage, ppp, ppp, 0, true, true); m_docMutex->unlock(); resizeContents ( m_outputdev->getImage().width ( ), m_outputdev->getImage().height ( )); viewport()->update(); } } bool PageWidget::readUp() { if( atTop() ) return false; else { int newValue = QMAX( verticalScrollBar()->value() - height() + 50, verticalScrollBar()->minValue() ); /* int step = 10; int value = verticalScrollBar()->value(); while( value > newValue - step ) { verticalScrollBar()->setValue( value ); value -= step; } */ verticalScrollBar()->setValue( newValue ); return true; } } void PageWidget::dropEvent( QDropEvent* ev ) { KURL::List lst; if ( KURLDrag::decode( ev, lst ) ) { emit urlDropped( lst.first() ); } } void PageWidget::dragEnterEvent( QDragEnterEvent * ev ) { ev->accept(); } bool PageWidget::readDown() { if( atBottom() ) return false; else { int newValue = QMIN( verticalScrollBar()->value() + height() - 50, verticalScrollBar()->maxValue() ); /* int step = 10; int value = verticalScrollBar()->value(); while( value < newValue + step ) { verticalScrollBar()->setValue( value ); value += step; } */ verticalScrollBar()->setValue( newValue ); return true; } } bool PageWidget::find(Unicode *u, int len, bool next) { bool b; if (!next) { // ensure we are searching the whole page m_xMin = 0; m_yMin = 0; } b = m_outputdev -> find(u, len, !next, true, next, false, &m_xMin, &m_yMin, &m_xMax, &m_yMax); m_xMin = m_xMin / m_zoomFactor; m_yMin = m_yMin / m_zoomFactor; m_xMax = m_xMax / m_zoomFactor; m_yMax = m_yMax / m_zoomFactor; m_selection = b; updateContents(); return b; } } // vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/kpdf_pagewidget.h b/kpdf/kpdf_pagewidget.h index 446fde369..2d4672ff3 100644 --- a/kpdf/kpdf_pagewidget.h +++ b/kpdf/kpdf_pagewidget.h @@ -1,113 +1,158 @@ /*************************************************************************** * Copyright (C) 2002 by Wilco Greven * * Copyright (C) 2003 by Christophe Devriese * * * * Copyright (C) 2003 by Laurent Montel * * Copyright (C) 2003 by Kurt Pfeifle * * 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. * ***************************************************************************/ #ifndef _KPDF_PAGEWIDGET_H_ #define _KPDF_PAGEWIDGET_H_ #include +#include "document.h" #include "CharTypes.h" class KURL; class QMutex; class QWidget; class LinkAction; class PDFDoc; class QOutputDev; namespace KPDF { /** * Widget displaying a pixmap containing a PDF page and Links. */ - class PageWidget : public QScrollView + class PageWidget : public QScrollView, public KPDFDocumentObserver { Q_OBJECT enum ZoomMode { FitInWindow, FitWidth, FitVisible, FixedFactor }; public: PageWidget(QWidget* parent, const char* name, QMutex *docMutex); ~PageWidget(); void setPDFDocument(PDFDoc*); void setPixelsPerPoint(float); /* void setLinks(); */ + // inherited from KPDFDocumentObserver + void pageSetup( const QValueList & /*pages*/ ) + {/* + m_outputDev->setPDFDocument(d->pdfdoc); + */} + void pageSetCurrent( int /*pageNumber*/, float /*position*/ ) + { + //m_pageWidget->setPage(m_currentPage); + } + void setPage(int pagenum); void enableScrollBars( bool b ); /** * Return true if the top resp. bottom of the page is visible. */ bool atTop() const; bool atBottom() const; void zoomTo( double _value ); bool find(Unicode *u, int len, bool next); public slots: void zoomIn(); void zoomOut(); void updatePixmap(); void scrollUp(); void scrollDown(); void scrollRight(); void scrollLeft(); void scrollBottom(); void scrollTop(); bool readUp(); bool readDown(); signals: void linkClicked(LinkAction*); void ReadUp(); void ReadDown(); void ZoomOut(); void ZoomIn(); void rightClick(); void urlDropped( const KURL& ); void spacePressed(); protected: virtual void keyPressEvent( QKeyEvent* ); void contentsMousePressEvent(QMouseEvent*); void contentsMouseReleaseEvent(QMouseEvent*); void contentsMouseMoveEvent(QMouseEvent*); virtual void wheelEvent( QWheelEvent * ); virtual void drawContents ( QPainter *p, int, int, int, int ); virtual void dragEnterEvent( QDragEnterEvent* ); virtual void dropEvent( QDropEvent* ); private: QOutputDev *m_outputdev; PDFDoc* m_doc; QMutex* m_docMutex; float m_ppp; // Pixels per point float m_zoomFactor; ZoomMode m_zoomMode; // first page is page 1 int m_currentPage; QPoint m_dragGrabPos; LinkAction* m_pressedAction; bool m_selection; double m_xMin, m_yMin, m_xMax, m_yMax; }; } +/* + ZoomMode m_zoomMode; + float m_zoomFactor; + // Do with these first. We can always add the other zoommodes which can + // be specified in a Destination later. + enum ZoomMode { FitInWindow, FitWidth, FitVisible, FixedFactor }; +*/ + +/* + connect( m_pageWidget, SIGNAL( ReadUp() ), SLOT( slotReadUp() )); + connect( m_pageWidget, SIGNAL( ReadDown() ), SLOT( slotReadDown() )); + connect( m_pageWidget, SIGNAL( spacePressed() ), this, SLOT( slotReadDown() ) ); +void Part::slotReadUp() +{ + if( !m_doc ) + return; + + if( !m_pageWidget->readUp() ) { + if ( previousPage() ) + m_pageWidget->scrollBottom(); + } +} +void Part::slotReadDown() +{ + if( !m_doc ) + return; + + if( !m_pageWidget->readDown() ) { + if ( nextPage() ) + m_pageWidget->scrollTop(); + } +} +*/ + #endif // vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/kpdf_part.cpp b/kpdf/kpdf_part.cpp index 6e4cebeb3..b8e8e8c17 100644 --- a/kpdf/kpdf_part.cpp +++ b/kpdf/kpdf_part.cpp @@ -1,846 +1,645 @@ /*************************************************************************** * Copyright (C) 2002 by Wilco Greven * * Copyright (C) 2002 by Chris Cheney * * Copyright (C) 2002 by Malcolm Hunter * * Copyright (C) 2003-2004 by Christophe Devriese * * * * Copyright (C) 2003 by Daniel Molkentin * * Copyright (C) 2003 by Andy Goossens * * Copyright (C) 2003 by Dirk Mueller * * Copyright (C) 2003 by Laurent Montel * * Copyright (C) 2004 by Dominique Devriese * * Copyright (C) 2004 by Christoph Cullmann * * Copyright (C) 2004 by Henrique Pinto * * Copyright (C) 2004 by Waldo Bastian * * Copyright (C) 2004 by Albert Astals Cid * * Copyright (C) 2004 by Antti Markus * * * * 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 "kpdf_part.moc" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include "kpdf_error.h" #include "GString.h" #include "GlobalParams.h" -#include "PDFDoc.h" -#include "TextOutputDev.h" #include "QOutputDevKPrinter.h" #include "thumbnaillist.h" #include "kpdf_pagewidget.h" +#include "document.h" typedef KParts::GenericFactory KPDFPartFactory; K_EXPORT_COMPONENT_FACTORY(libkpdfpart, KPDFPartFactory) using namespace KPDF; unsigned int Part::m_count = 0; Part::Part(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList & /*args*/ ) - : KParts::ReadOnlyPart(parent, name), - m_doc(0), - m_currentPage(0), - m_zoomMode(FixedFactor), - m_zoomFactor(1.0) + : KParts::ReadOnlyPart(parent, name) { - new BrowserExtension(this); + // create browser extension (for printing when embedded into browser) + new BrowserExtension(this); - globalParams = new GlobalParams(""); + // xpdf 'extern' global class (m_count is a static instance counter) TODO check for wasted creation + globalParams = new GlobalParams(""); + m_count++; - // we need an instance - setInstance(KPDFPartFactory::instance()); + // we need an instance + setInstance(KPDFPartFactory::instance()); - QHBox *widget = new QHBox(parentWidget, widgetName); - widget->setSpacing(3); - widget->setMargin(3); - - m_thumbnailList = new ThumbnailList(widget, &m_docMutex); - m_thumbnailList->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)7, 0, 0, m_thumbnailList->sizePolicy().hasHeightForWidth() ) ); - m_thumbnailList->setMaximumSize( QSize( 75, 32767 ) ); - m_thumbnailList->setColumnWidth(0, 75); - - m_outputDev = new KPDF::PageWidget( widget, "outputdev", &m_docMutex ); - // is this really necessaty?? - widget->resize( QSize(623, 381).expandedTo(widget->minimumSizeHint()) ); - - connect(m_thumbnailList, SIGNAL(clicked(int)), this, SLOT(pageClicked(int))); - connect(m_outputDev, SIGNAL(rightClick()), this, SIGNAL(rightClick())); - - m_outputDev->setAcceptDrops( true ); - - setWidget(widget); - - m_showScrollBars = new KToggleAction( i18n( "Show &Scrollbars" ), 0, - actionCollection(), "show_scrollbars" ); - m_showScrollBars->setCheckedState(i18n("Hide &Scrollbars")); - m_showPageList = new KToggleAction( i18n( "Show &Page List" ), 0, - actionCollection(), "show_page_list" ); - m_showPageList->setCheckedState(i18n("Hide &Page List")); - connect( m_showScrollBars, SIGNAL( toggled( bool ) ), - SLOT( showScrollBars( bool ) ) ); - connect( m_showPageList, SIGNAL( toggled( bool ) ), - SLOT( showMarkList( bool ) ) ); - - // create our actions - KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection(), "save"); - m_find = KStdAction::find(this, SLOT(find()), - actionCollection(), "find"); - m_find->setEnabled(false); - m_findNext = KStdAction::findNext(this, SLOT(findNext()), - actionCollection(), "find_next"); - m_findNext->setEnabled(false); - m_fitToWidth = new KToggleAction(i18n("Fit to Page &Width"), 0, - this, SLOT(slotFitToWidthToggled()), - actionCollection(), "fit_to_width"); - KStdAction::zoomIn (m_outputDev, SLOT(zoomIn()), - actionCollection(), "zoom_in"); - KStdAction::zoomOut (m_outputDev, SLOT(zoomOut()), - actionCollection(), "zoom_out"); - - KStdAction::back (this, SLOT(back()), - actionCollection(), "back"); - KStdAction::forward (this, SLOT(forward()), - actionCollection(), "forward"); - - KStdAction::printPreview( this, SLOT( printPreview() ), actionCollection() ); - - m_prevPage = KStdAction::prior(this, SLOT(slotPreviousPage()), - actionCollection(), "previous_page"); - m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); - - m_nextPage = KStdAction::next(this, SLOT(slotNextPage()), - actionCollection(), "next_page" ); - m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); - - m_firstPage = KStdAction::firstPage( this, SLOT( slotGotoStart() ), - actionCollection(), "goToStart" ); - m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) ); - - m_lastPage = KStdAction::lastPage( this, SLOT( slotGotoEnd() ), - actionCollection(), "goToEnd" ); - m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) ); - - m_gotoPage = KStdAction::gotoPage( this, SLOT( slotGoToPage() ), - actionCollection(), "goToPage" ); - - const double zoomValue[14] = {0.125,0.25,0.3333,0.5,0.6667,0.75,1,1.25,1.50,2,3,4,6,8 }; - - m_zoomTo = new KSelectAction( i18n( "Zoom" ), "zoomTo", 0, actionCollection(), "zoomTo" ); - connect( m_zoomTo, SIGNAL( activated( const QString & ) ), this, SLOT( slotZoom( const QString& ) ) ); - m_zoomTo->setEditable( true ); - m_zoomTo->clear(); - - QStringList translated; - QString localValue; - QString double_oh("00"); - int idx = 0; - int cur = 0; - for ( int i = 0; i < 10;i++) - { - localValue = KGlobal::locale()->formatNumber( zoomValue[i] * 100.0, 2 ); - localValue.remove( KGlobal::locale()->decimalSymbol()+double_oh ); + // build widgets + QHBox *widget = new QHBox(parentWidget, widgetName); + widget->setSpacing(3); + widget->setMargin(3); - translated << QString( "%1%" ).arg( localValue ); - if ( zoomValue[i] == 1.0 ) - idx = cur; - ++cur; - } + m_thumbnailList = new ThumbnailList(widget, &m_docMutex); + m_thumbnailList->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)7, 0, 0, m_thumbnailList->sizePolicy().hasHeightForWidth() ) ); + m_thumbnailList->setMaximumSize( QSize( 75, 32767 ) ); + m_thumbnailList->setColumnWidth(0, 75); - m_zoomTo->setItems( translated ); - m_zoomTo->setCurrentItem( idx ); - - - // set our XML-UI resource file - setXMLFile("kpdf_part.rc"); - connect( m_outputDev, SIGNAL( ZoomIn() ), SLOT( zoomIn() )); - connect( m_outputDev, SIGNAL( ZoomOut() ), SLOT( zoomOut() )); - connect( m_outputDev, SIGNAL( ReadUp() ), SLOT( slotReadUp() )); - connect( m_outputDev, SIGNAL( ReadDown() ), SLOT( slotReadDown() )); - connect( m_outputDev, SIGNAL( urlDropped( const KURL& ) ), SLOT( slotOpenUrlDropped( const KURL & ))); - connect( m_outputDev, SIGNAL( spacePressed() ), this, SLOT( slotReadDown() ) ); - readSettings(); - updateActionPage(); - m_count++; -} + m_pageWidget = new KPDF::PageWidget( widget, "outputdev", &m_docMutex ); + connect( m_pageWidget, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURL( const KURL & ))); + //connect(m _pageWidget, SIGNAL( rightClick() ), this, SIGNAL( rightClick() )); -Part::~Part() -{ - m_count--; - m_thumbnailList->stopThumbnailGeneration(); - writeSettings(); - if (m_count == 0) delete globalParams; - delete m_doc; -} + // FIXME is the following line really necessary?? + widget->resize( QSize(623, 381).expandedTo(widget->minimumSizeHint()) ); + setWidget(widget); -void Part::slotZoom( const QString&nz ) -{ - QString z = nz; - double zoom; - z.remove( z.find( '%' ), 1 ); - bool isNumber = true; - zoom = KGlobal::locale()->readNumber( z, &isNumber ) / 100; - - if ( isNumber ) - { - kdDebug() << "ZOOM = " << nz << ", setting zoom = " << zoom << endl; - m_outputDev->zoomTo( zoom ); - } + // build the document + document = new KPDFDocument(); + connect( document, SIGNAL( pageChanged() ), this, SLOT( updateActions() ) ); + document->addObserver( m_thumbnailList ); + document->addObserver( m_pageWidget ); + + // ACTIONS + KActionCollection * ac = actionCollection(); + + // Page Traversal actions + m_gotoPage = KStdAction::gotoPage( this, SLOT( slotGoToPage() ), ac, "goToPage" ); + + m_prevPage = KStdAction::prior(this, SLOT(slotPreviousPage()), ac, "previous_page"); + m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) ); + + m_nextPage = KStdAction::next(this, SLOT(slotNextPage()), ac, "next_page" ); + m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) ); + + m_firstPage = KStdAction::firstPage( this, SLOT( slotGotoStart() ), ac, "goToStart" ); + m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) ); + + m_lastPage = KStdAction::lastPage( this, SLOT( slotGotoEnd() ), ac, "goToEnd" ); + m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) ); + + // Find actions + m_find = KStdAction::find(this, SLOT(slotFind()), ac, "find"); + m_find->setEnabled(false); + + m_findNext = KStdAction::findNext(this, SLOT(slotFindNext()), ac, "find_next"); + m_findNext->setEnabled(false); + + // Zoom actions + const double zoomValue[14] = {0.125,0.25,0.3333,0.5,0.6667,0.75,1,1.25,1.50,2,3,4,6,8 }; + + m_zoomTo = new KSelectAction( i18n( "Zoom" ), "zoomTo", 0, ac, "zoomTo" ); + connect( m_zoomTo, SIGNAL( activated( const QString & ) ), this, SLOT( slotZoom( const QString& ) ) ); + m_zoomTo->setEditable( true ); + m_zoomTo->clear(); + + QStringList translated; + QString localValue; + QString double_oh("00"); + int idx = 0; + int cur = 0; + for ( int i = 0; i < 10;i++) + { + localValue = KGlobal::locale()->formatNumber( zoomValue[i] * 100.0, 2 ); + localValue.remove( KGlobal::locale()->decimalSymbol()+double_oh ); + + translated << QString( "%1%" ).arg( localValue ); + if ( zoomValue[i] == 1.0 ) + idx = cur; + ++cur; + } + m_zoomTo->setItems( translated ); + m_zoomTo->setCurrentItem( idx ); + + KStdAction::zoomIn( m_pageWidget, SLOT(zoomIn()), ac, "zoom_in" ); + + KStdAction::zoomOut( m_pageWidget, SLOT(zoomOut()), ac, "zoom_out" ); + + m_fitToWidth = new KToggleAction( i18n("Fit to Page &Width"), 0, ac, "fit_to_width" ); + connect( m_fitToWidth, SIGNAL( toggled( bool ) ), SLOT( slotFitToWidthToggled( bool ) ) ); + + // other actions (printing, show/hide stuff, saving) + KStdAction::printPreview( this, SLOT( slotPrintPreview() ), ac ); + + m_showScrollBars = new KToggleAction( i18n( "Show &Scrollbars" ), 0, ac, "show_scrollbars" ); + m_showScrollBars->setCheckedState(i18n("Hide &Scrollbars")); + connect( m_showScrollBars, SIGNAL( toggled( bool ) ), SLOT( slotToggleScrollBars( bool ) ) ); + + m_showPageList = new KToggleAction( i18n( "Show &Page List" ), 0, ac, "show_page_list" ); + m_showPageList->setCheckedState(i18n("Hide &Page List")); + connect( m_showPageList, SIGNAL( toggled( bool ) ), SLOT( slotToggleThumbnails( bool ) ) ); + + KStdAction::saveAs(this, SLOT(slotSaveFileAs()), ac, "save"); + + // set our XML-UI resource file + setXMLFile("kpdf_part.rc"); + readSettings(); + updateActions(); } -void Part::slotGoToPage() +// ### + +Part::~Part() { - if ( m_doc ) - { - bool ok = false; - int num = KInputDialog::getInteger(i18n("Go to Page"), i18n("Page:"), m_currentPage, - 1, m_doc->getNumPages(), 1, 10, &ok/*, _part->widget()*/); - if (ok) - goToPage( num ); - } + delete document; + writeSettings(); + if ( --m_count == 0 ) + delete globalParams; } -void Part::goToPage( int page ) +void Part::slotZoom( const QString & nz ) { - if (page != m_currentPage) - { - m_currentPage = page; - m_thumbnailList->setCurrentThumbnail(m_currentPage); - m_outputDev->setPage(m_currentPage); - updateActionPage(); - } + QString z = nz; + z.remove( z.find( '%' ), 1 ); + bool isNumber = true; + double zoom = KGlobal::locale()->readNumber( z, &isNumber ) / 100; + + if ( isNumber ) + document->setZoom( zoom ); } -void Part::slotOpenUrlDropped( const KURL &url ) +void Part::slotZoomIn() { - openURL(url); + document->zoom( 0.1 ); } -void Part::updateActionPage() +void Part::slotZoomOut() { - if ( m_doc ) - { - m_firstPage->setEnabled(m_currentPage>1); - m_lastPage->setEnabled(m_currentPagegetNumPages()); - m_prevPage->setEnabled(m_currentPage>1); - m_nextPage->setEnabled(m_currentPagegetNumPages()); - } - else - { - m_firstPage->setEnabled(false); - m_lastPage->setEnabled(false); - m_prevPage->setEnabled(false); - m_nextPage->setEnabled(false); - } + document->zoom( -0.1 ); } -void Part::slotReadUp() +void Part::slotGoToPage() { - if( !m_doc ) - return; - - if( !m_outputDev->readUp() ) { - if ( previousPage() ) - m_outputDev->scrollBottom(); - } + bool ok = false; + //TODO a better dialog with a slider too + int num = KInputDialog::getInteger(i18n("Go to Page"), i18n("Page:"), document->currentPage(), + 1, document->pages(), 1, 10, &ok/*, _part->widget()*/); + if (ok) + document->setCurrentPage( num ); } -void Part::slotReadDown() +void Part::updateActions() { - if( !m_doc ) - return; - - if( !m_outputDev->readDown() ) { - if ( nextPage() ) - m_outputDev->scrollTop(); - } + if ( document->pages() > 0 ) + { + m_firstPage->setEnabled( !document->atBegin() ); + m_prevPage->setEnabled( !document->atBegin() ); + m_lastPage->setEnabled( !document->atEnd() ); + m_nextPage->setEnabled( !document->atEnd() ); + } + else + { + m_firstPage->setEnabled(false); + m_lastPage->setEnabled(false); + m_prevPage->setEnabled(false); + m_nextPage->setEnabled(false); + } } void Part::writeSettings() { - KConfigGroup general( KPDFPartFactory::instance()->config(), "General" ); - general.writeEntry( "ShowScrollBars", m_showScrollBars->isChecked() ); - general.writeEntry( "ShowPageList", m_showPageList->isChecked() ); - general.sync(); + KConfigGroup general( KPDFPartFactory::instance()->config(), "General" ); + general.writeEntry( "ShowScrollBars", m_showScrollBars->isChecked() ); + general.writeEntry( "ShowPageList", m_showPageList->isChecked() ); + general.sync(); } void Part::readSettings() { - KConfigGroup general( KPDFPartFactory::instance()->config(), "General" ); - m_showScrollBars->setChecked( general.readBoolEntry( "ShowScrollBars", true ) ); - showScrollBars( m_showScrollBars->isChecked() ); - m_showPageList->setChecked( general.readBoolEntry( "ShowPageList", true ) ); - showMarkList( m_showPageList->isChecked() ); + KConfigGroup general( KPDFPartFactory::instance()->config(), "General" ); + m_showScrollBars->setChecked( general.readBoolEntry( "ShowScrollBars", true ) ); + slotToggleScrollBars( m_showScrollBars->isChecked() ); + m_showPageList->setChecked( general.readBoolEntry( "ShowPageList", true ) ); + slotToggleThumbnails( m_showPageList->isChecked() ); } -void Part::showScrollBars( bool show ) +void Part::slotToggleScrollBars( bool show ) { - m_outputDev->enableScrollBars( show ); + m_pageWidget->enableScrollBars( show ); } -void Part::showMarkList( bool show ) +void Part::slotToggleThumbnails( bool show ) { - if (show) m_thumbnailList->show(); - else m_thumbnailList->hide(); + m_thumbnailList->setShown( show ); } void Part::slotGotoEnd() { - if ( m_doc && m_doc->getNumPages() > 0 ) - { - goToPage(m_doc->getNumPages()); - } + document->setCurrentPage( document->pages() - 1 ); } void Part::slotGotoStart() { - if ( m_doc && m_doc->getNumPages() > 0 ) - { - goToPage(1); - } -} - -bool Part::nextPage() -{ - if ( m_doc && m_currentPage + 1 > m_doc->getNumPages()) return false; - - goToPage(m_currentPage+1); - return true; + document->setCurrentPage( 0 ); } void Part::slotNextPage() { - nextPage(); + if ( !document->atEnd() ) + document->setCurrentPage( document->currentPage() + 1 ); } void Part::slotPreviousPage() { - previousPage(); -} - -bool Part::previousPage() -{ - if (m_currentPage - 1 < 1) return false; - - goToPage(m_currentPage-1); - return true; + if ( !document->atBegin() ) + document->setCurrentPage( document->currentPage() - 1 ); } - KAboutData* -Part::createAboutData() +KAboutData* Part::createAboutData() { - // the non-i18n name here must be the same as the directory in - // which the part's rc file is installed ('partrcdir' in the - // Makefile) - KAboutData* aboutData = new KAboutData("kpdfpart", I18N_NOOP("KPDF::Part"), - "0.1"); - aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org"); - return aboutData; + // the non-i18n name here must be the same as the directory in + // which the part's rc file is installed ('partrcdir' in the + // Makefile) + KAboutData* aboutData = new KAboutData("kpdfpart", I18N_NOOP("KPDF::Part"), "0.1"); + aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org"); + return aboutData; } - bool -Part::closeURL() +bool Part::openFile() { - m_thumbnailList->stopThumbnailGeneration(); - delete m_doc; - m_doc = 0; - - return KParts::ReadOnlyPart::closeURL(); + bool ok = document->openFile( m_file ); + m_find->setEnabled(ok); + m_findNext->setEnabled(ok); + return ok; } - bool -Part::openFile() +bool Part::closeURL() { - // m_file is always local so we can use QFile on it - QFile file(m_file); - if (file.open(IO_ReadOnly) == false) - return false; - file.close(); - - GString* filename = new GString( QFile::encodeName( m_file ) ); - m_doc = new PDFDoc(filename, 0, 0); - - if (!m_doc->isOk()) - return false; - - m_find->setEnabled(true); - m_findNext->setEnabled(true); - - errors::clear(); - m_currentPage = 0; //so that the if in goToPage is true - if (m_doc->getNumPages() > 0) - { - // TODO use a qvaluelist to pass aspect ratio? - // TODO move it the thumbnail list? - m_thumbnailList->setPages(m_doc->getNumPages(), m_doc->getPageHeight(1)/m_doc->getPageWidth(1)); - m_thumbnailList->generateThumbnails(m_doc); - - m_outputDev->setPDFDocument(m_doc); - goToPage(1); - - } - - return true; + document->close(); + return KParts::ReadOnlyPart::closeURL(); } - void -Part::fileSaveAs() +void Part::slotSaveFileAs() { KURL saveURL = KFileDialog::getSaveURL( url().isLocalFile() ? url().url() : url().fileName(), QString::null, widget(), QString::null ); if( !KIO::NetAccess::upload( url().path(), saveURL, static_cast( 0 ) ) ) ; // TODO: Proper error dialog - } - void -Part::displayPage(int pageNumber, float /*zoomFactor*/) +void Part::displayPage( int /*pageNumber*/ ) { +/* if (pageNumber <= 0 || pageNumber > m_doc->getNumPages()) return; - updateActionPage(); + updateActions(); const double pageWidth = m_doc->getPageWidth (pageNumber) * m_zoomFactor; const double pageHeight = m_doc->getPageHeight(pageNumber) * m_zoomFactor; // Pixels per point when the zoomFactor is 1. const float basePpp = QPaintDevice::x11AppDpiX() / 72.0; switch (m_zoomMode) { case FitWidth: { const double pageAR = pageWidth/pageHeight; // Aspect ratio - const int canvasWidth = m_outputDev->contentsRect().width(); - const int canvasHeight = m_outputDev->contentsRect().height(); - const int scrollBarWidth = m_outputDev->verticalScrollBar()->width(); + const int canvasWidth = m_pageWidget->contentsRect().width(); + const int canvasHeight = m_pageWidget->contentsRect().height(); + const int scrollBarWidth = m_pageWidget->verticalScrollBar()->width(); // Calculate the height so that the page fits the viewport width // assuming that we need a vertical scrollbar. float height = float(canvasWidth - scrollBarWidth) / pageAR; // If the vertical scrollbar wasn't needed after all, calculate the page // size so that the page fits the viewport width without the scrollbar. if (ceil(height) <= canvasHeight) { height = float(canvasWidth) / pageAR; // Handle the rare case that enlarging the page resulted in the need of // a vertical scrollbar. We can fit the page to the viewport height in // this case. if (ceil(height) > canvasHeight) height = float(canvasHeight) * pageAR; } m_zoomFactor = (height / pageHeight) / basePpp; break; } case FixedFactor: default: break; } - +*/ //const float ppp = basePpp * m_zoomFactor; // pixels per point - -// m_doc->displayPage(m_outputDev, pageNumber, int(m_zoomFactor * ppp * 72.0), 0, true); - -// m_outputDev->show(); - +// m_doc->displayPage(m_pageWidget, pageNumber, int(m_zoomFactor * ppp * 72.0), 0, true); +// m_pageWidget->show(); // m_currentPage = pageNumber; } /* - void -Part::displayDestination(LinkDest* dest) +void Part::displayDestination(LinkDest* dest) { int pageNumber; // int dx, dy; if (dest->isPageRef()) { Ref pageRef = dest->getPageRef(); pageNumber = m_doc->findPage(pageRef.num, pageRef.gen); } else { pageNumber = dest->getPageNum(); } if (pageNumber <= 0 || pageNumber > m_doc->getNumPages()) { pageNumber = 1; } displayPage(pageNumber); return; if (fullScreen) { return; } switch (dest->getKind()) { case destXYZ: out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); if (dest->getChangeLeft() || dest->getChangeTop()) { if (dest->getChangeLeft()) { hScrollbar->setPos(dx, canvas->getWidth()); } if (dest->getChangeTop()) { vScrollbar->setPos(dy, canvas->getHeight()); } canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); } //~ what is the zoom parameter? break; case destFit: case destFitB: //~ do fit hScrollbar->setPos(0, canvas->getWidth()); vScrollbar->setPos(0, canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case destFitH: case destFitBH: //~ do fit out->cvtUserToDev(0, dest->getTop(), &dx, &dy); hScrollbar->setPos(0, canvas->getWidth()); vScrollbar->setPos(dy, canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case destFitV: case destFitBV: //~ do fit out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy); hScrollbar->setPos(dx, canvas->getWidth()); vScrollbar->setPos(0, canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; case destFitR: //~ do fit out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); hScrollbar->setPos(dx, canvas->getWidth()); vScrollbar->setPos(dy, canvas->getHeight()); canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); break; } }*/ - void -Part::print() -{ - if (m_doc == 0) - return; - - double width, height; - int landscape, portrait; - KPrinter printer; - - printer.setPageSelection(KPrinter::ApplicationSide); - printer.setMinMax(1, m_doc->getNumPages()); - printer.setCurrentPage(m_currentPage); - printer.setMargins(0, 0, 0, 0); - - // if some pages are landscape and others are not the most common win as kprinter does - // not accept a per page setting - landscape = 0; - portrait = 0; - for (int i = 1; i <= m_doc->getNumPages(); i++) - { - width = m_doc->getPageWidth(i); - height = m_doc->getPageHeight(i); - if (m_doc->getPageRotate(i) == 90 || m_doc->getPageRotate(i) == 270) qSwap(width, height); - if (width > height) landscape++; - else portrait++; - } - if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); - - if (printer.setup(widget())) - { - doPrint( printer ); - } -} - /* - void -Part::setFixedZoomFactor(float zoomFactor) -{ - -} -*/ -/* - void -Part::executeAction(LinkAction* action) +void Part::executeAction(LinkAction* action) { if (action == 0) return; LinkActionKind kind = action->getKind(); switch (kind) { case actionGoTo: case actionGoToR: { LinkDest* dest = 0; GString* namedDest = 0; if (kind == actionGoTo) { if ((dest = ((LinkGoTo*)action)->getDest())) dest = dest->copy(); else if ((namedDest = ((LinkGoTo*)action)->getNamedDest())) namedDest = namedDest->copy(); } else { if ((dest = ((LinkGoToR*)action)->getDest())) dest = dest->copy(); else if ((namedDest = ((LinkGoToR*)action)->getNamedDest())) namedDest = namedDest->copy(); s = ((LinkGoToR*)action)->getFileName()->getCString(); //~ translate path name for VMS (deal with '/') if (!loadFile(fileName)) { delete dest; delete namedDest; return; } } if (namedDest != 0) { dest = m_doc->findDest(namedDest); delete namedDest; } if (dest != 0) { displayDestination(dest); delete dest; } else { if (kind == actionGoToR) displayPage(1); } break; } default: break; } }*/ -void Part::slotFitToWidthToggled() -{ - m_zoomMode = m_fitToWidth->isChecked() ? FitWidth : FixedFactor; - displayPage(m_currentPage); -} - -// for optimization -bool redrawing = false; - -void Part::update() -{ - if (m_outputDev && ! redrawing) - { - redrawing = true; - QTimer::singleShot(200, this, SLOT( redrawPage() )); - } -} - -void Part::redrawPage() +void Part::slotFitToWidthToggled( bool /*fit*/ ) { - redrawing = false; +/* + m_zoomMode = m_fitToWidth->isChecked() ? FitWidth : FixedFactor; displayPage(m_currentPage); +*/ } -void Part::pageClicked ( int i ) -{ - goToPage(i); -} -BrowserExtension::BrowserExtension(Part* parent) - : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" ) +void Part::slotPrint() { - emit enableAction("print", true); - setURLDropHandlingEnabled(true); -} +/* + if (m_doc == 0) + return; - void -BrowserExtension::print() -{ - static_cast(parent())->print(); + double width, height; + int landscape, portrait; + KPrinter printer; + + printer.setPageSelection(KPrinter::ApplicationSide); + printer.setMinMax(1, m_doc->getNumPages()); + printer.setCurrentPage(m_currentPage); + printer.setMargins(0, 0, 0, 0); + + // if some pages are landscape and others are not the most common win as kprinter does + // not accept a per page setting + landscape = 0; + portrait = 0; + for (int i = 1; i <= m_doc->getNumPages(); i++) + { + width = m_doc->getPageWidth(i); + height = m_doc->getPageHeight(i); + if (m_doc->getPageRotate(i) == 90 || m_doc->getPageRotate(i) == 270) qSwap(width, height); + if (width > height) landscape++; + else portrait++; + } + if (landscape > portrait) printer.setOrientation(KPrinter::Landscape); + + if (printer.setup(widget())) + { + doPrint( printer ); + } +*/ } -void Part::printPreview() +void Part::slotPrintPreview() { +/* if (m_doc == 0) return; double width, height; int landscape, portrait; KPrinter printer; printer.setMinMax(1, m_doc->getNumPages()); printer.setPreviewOnly( true ); printer.setMargins(0, 0, 0, 0); // if some pages are landscape and others are not the most common win as kprinter does // not accept a per page setting landscape = 0; portrait = 0; for (int i = 1; i <= m_doc->getNumPages(); i++) { width = m_doc->getPageWidth(i); height = m_doc->getPageHeight(i); if (m_doc->getPageRotate(i) == 90 || m_doc->getPageRotate(i) == 270) qSwap(width, height); if (width > height) landscape++; else portrait++; } if (landscape > portrait) printer.setOption("orientation-requested", "4"); doPrint(printer); +*/ } -void Part::doPrint( KPrinter& printer ) +void Part::doPrint( KPrinter& /*printer*/ ) { +/* QPainter painter( &printer ); SplashColor paperColor; paperColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff); QOutputDevKPrinter printdev( painter, paperColor, printer ); printdev.startDoc(m_doc->getXRef()); QValueList pages = printer.pageList(); for ( QValueList::ConstIterator i = pages.begin(); i != pages.end();) { m_docMutex.lock(); m_doc->displayPage(&printdev, *i, printer.resolution(), printer.resolution(), 0, true, true); if ( ++i != pages.end() ) printer.newPage(); m_docMutex.unlock(); } +*/ } -void Part::find() -{ - KFindDialog dlg(widget()); - if (dlg.exec() != QDialog::Accepted) return; +//temp +#include - doFind(dlg.pattern(), false); +void Part::slotFind() +{ + KFindDialog dlg(widget()); + if (dlg.exec() == QDialog::Accepted) + document->find( false, dlg.pattern() ); } -void Part::findNext() +void Part::slotFindNext() { - if (!m_findText.isEmpty()) doFind(m_findText, true); + //if (!m_findText.isEmpty()) + document->find( true ); } -void Part::doFind(QString s, bool next) +/* +* BrowserExtension class +*/ +BrowserExtension::BrowserExtension(Part* parent) + : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" ) { - TextOutputDev *textOut; - Unicode *u; - bool found; - double xMin1, yMin1, xMax1, yMax1; - int len, pg; - - // This is more or less copied from what xpdf does, surely can be optimized - len = s.length(); - u = (Unicode *)gmalloc(len * sizeof(Unicode)); - for (int i = 0; i < len; ++i) u[i] = (Unicode)(s.latin1()[i] & 0xff); - - // search current - found = m_outputDev->find(u, len, next); - - if (!found) - { - // search following pages - textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse); - if (!textOut->isOk()) - { - gfree(u); - delete textOut; - return; - } - - pg = m_currentPage + 1; - while(!found && pg <= m_doc->getNumPages()) - { - m_docMutex.lock(); - m_doc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse); - m_docMutex.unlock(); - found = textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, &xMin1, &yMin1, &xMax1, &yMax1); - if (!found) pg++; - } - - if (!found && m_currentPage != 1) - { - if (KMessageBox::questionYesNo(widget(), i18n("End of document reached.\nContinue from the beginning?")) == KMessageBox::Yes) - { - // search previous pages - pg = 1; - while(!found && pg < m_currentPage) - { - m_docMutex.lock(); - m_doc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse); - m_docMutex.unlock(); - found = textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, &xMin1, &yMin1, &xMax1, &yMax1); - if (!found) pg++; - } - } - } - - delete textOut; - if (found) - { - kdDebug() << "found at " << pg << endl; - goToPage(pg); - // xpdf says: can happen that we do not find the text if coalescing is bad OUCH - m_outputDev->find(u, len, false); - } - else - { - if (next) KMessageBox::information(widget(), i18n("No more matches found for '%1'.").arg(s)); - else KMessageBox::information(widget(), i18n("No matches found for '%1'.").arg(s)); - } - } - - if (found) m_findText = s; - else m_findText = QString::null; + emit enableAction("print", true); + setURLDropHandlingEnabled(true); +} - gfree(u); +void BrowserExtension::print() +{ + static_cast(parent())->slotPrint(); } // vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/kpdf_part.h b/kpdf/kpdf_part.h index df17186d6..bd5dec135 100644 --- a/kpdf/kpdf_part.h +++ b/kpdf/kpdf_part.h @@ -1,183 +1,158 @@ /*************************************************************************** * Copyright (C) 2002 by Wilco Greven * * Copyright (C) 2003-2004 by Christophe Devriese * * * * Copyright (C) 2003 by Andy Goossens * * Copyright (C) 2003 by Laurent Montel * * Copyright (C) 2004 by Dominique Devriese * * 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. * ***************************************************************************/ #ifndef _KPDF_PART_H_ #define _KPDF_PART_H_ #include #include #include class QWidget; class KAboutData; class KAction; class KPrinter; class KURL; class KToggleAction; class KSelectAction; class LinkAction; class LinkDest; -class PDFDoc; class XOutputDev; class ThumbnailList; class PDFPartView; +class KPDFDocument; + namespace KPDF { class BrowserExtension; class PageWidget; /** * This is a "Part". It that does all the real work in a KPart * application. * * @short Main Part * @author Wilco Greven - * @version 0.1 + * @version 0.2 */ class Part : public KParts::ReadOnlyPart { - Q_OBJECT + Q_OBJECT public: - // Do with these first. We can always add the other zoommodes which can - // be specified in a Destination later. - enum ZoomMode { FitInWindow, FitWidth, FitVisible, FixedFactor }; - - /** - * Default constructor - */ - Part(QWidget* parentWidget, const char* widgetName, - QObject* parent, const char* name, const QStringList& args); - - /** - * Destructor - */ - virtual ~Part(); - static KAboutData* createAboutData(); + /** + * Default constructor + */ + Part(QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, const QStringList& args); - bool closeURL(); + /** + * Destructor + */ + virtual ~Part(); - void displayPage(int pageNumber, float zoomFactor = 1.0); - /*void displayDestination(LinkDest*);*/ - void updateActionPage(); - PageWidget* pageWidget() const {return m_outputDev;} - - public slots: - void print(); + static KAboutData* createAboutData(); - signals: - void rightClick(); + // reimplemented from KParts::ReadOnlyPart + bool closeURL(); + void displayPage(int pageNumber ); //TODO REMOVE ME! protected: - /** - * This must be implemented by each part - */ - virtual bool openFile(); - - void update(); - void readSettings(); - void writeSettings(); - bool nextPage(); - bool previousPage(); - void updateAction(); - void goToPage( int page ); - void doPrint( KPrinter& printer ); + // reimplemented from KParts::ReadOnlyPart + virtual bool openFile(); + + void readSettings(); + void writeSettings(); + void updateAction(); + void doPrint( KPrinter& printer ); protected slots: - void find(); - void findNext(); - void zoomIn() { m_zoomFactor += 0.1; update(); }; - void zoomOut() { m_zoomFactor -= 0.1; update(); }; - void back() { /* stub */ }; - void forward() { /* stub */ }; - void slotNextPage(); - void slotPreviousPage(); - void slotGotoEnd(); - void slotGotoStart(); - void slotGoToPage(); - void printPreview(); - - /*void executeAction(LinkAction*);*/ - - void showScrollBars( bool ); - void showMarkList( bool ); - void slotReadUp(); - void slotReadDown(); - void slotOpenUrlDropped( const KURL & ); - void slotZoom( const QString& ); + // connected to actions + void slotGoToPage(); + void slotPreviousPage(); + void slotNextPage(); + void slotGotoStart(); + void slotGotoEnd(); + void slotFind(); + void slotFindNext(); + void slotZoom( const QString& ); + void slotZoomIn(); + void slotZoomOut(); + void slotFitToWidthToggled( bool ); + void slotPrintPreview(); + void slotToggleScrollBars( bool ); + void slotToggleThumbnails( bool ); + void slotSaveFileAs(); + // can be connected do widget elements + void updateActions(); + + public slots: + // connected to Shell action (and browserExtension), not local one + void slotPrint(); private: - void doFind(QString s, bool next); - - ThumbnailList *m_thumbnailList; - // TODO rename to something else - PageWidget* m_outputDev; - - PDFDoc* m_doc; - - KAction* m_firstPage; - KAction* m_lastPage; - KAction* m_prevPage; - KAction* m_nextPage; - KAction *m_gotoPage; - KToggleAction* m_showScrollBars; - KToggleAction* m_showPageList; - KSelectAction *m_zoomTo; - KToggleAction* m_fitToWidth; - KAction *m_find; - KAction *m_findNext; - - QString m_findText; - - // first page is page 1 - int m_currentPage; - QMutex m_docMutex; - - ZoomMode m_zoomMode; - float m_zoomFactor; - - static unsigned int m_count; - - private slots: - void slotFitToWidthToggled(); - void redrawPage(); - void pageClicked ( int ); - void fileSaveAs(); + +// PORT!! ### +// PDFDoc* m_doc; +QMutex m_docMutex; // REMOVE MEEE + + // the document + KPDFDocument * document; + + // main widgets + ThumbnailList *m_thumbnailList; + PageWidget *m_pageWidget; + + // static instances counter + static unsigned int m_count; + + // actions + KAction *m_gotoPage; + KAction *m_prevPage; + KAction *m_nextPage; + KAction *m_firstPage; + KAction *m_lastPage; + KToggleAction *m_showScrollBars; + KToggleAction *m_showPageList; + KSelectAction *m_zoomTo; + KToggleAction *m_fitToWidth; + KAction *m_find; + KAction *m_findNext; }; class BrowserExtension : public KParts::BrowserExtension { - Q_OBJECT + Q_OBJECT public: - BrowserExtension(Part*); + BrowserExtension(Part*); public slots: - // Automatically detected by the host. - void print(); + // Automatically detected by the host. + void print(); }; } #endif // vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/kpdf_shell.cpp b/kpdf/kpdf_shell.cpp index 8e0b18f62..40616b77d 100644 --- a/kpdf/kpdf_shell.cpp +++ b/kpdf/kpdf_shell.cpp @@ -1,222 +1,222 @@ /*************************************************************************** * Copyright (C) 2002 by Wilco Greven * * Copyright (C) 2002 by Chris Cheney * * Copyright (C) 2003 by Benjamin Meyer * * Copyright (C) 2003-2004 by Christophe Devriese * * * * Copyright (C) 2003 by Laurent Montel * * Copyright (C) 2003-2004 by Albert Astals Cid * * Copyright (C) 2003 by Luboš Luňák * * Copyright (C) 2003 by Malcolm Hunter * * Copyright (C) 2004 by Dominique Devriese * * Copyright (C) 2004 by Dirk Mueller * * * * 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 "kpdf_shell.h" #include "kpdf_shell.moc" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KPDF; Shell::Shell() : KParts::MainWindow(0, "KPDF::Shell") { // set the shell's ui resource file setXMLFile("kpdf_shell.rc"); // this routine will find and load our Part. it finds the Part by // name which is a bad idea usually.. but it's alright in this // case since our Part is made for this Shell KLibFactory *factory = KLibLoader::self()->factory("libkpdfpart"); if (factory) { // now that the Part is loaded, we cast it to a Part to get // our hands on it m_part = static_cast( factory->create(this, "kpdf_part", "KParts::ReadOnlyPart")); if (m_part) { // then, setup our actions setupActions(); // tell the KParts::MainWindow that this is indeed the main widget setCentralWidget(m_part->widget()); // and integrate the part's GUI with the shell's setupGUI(ToolBar | Keys | Save); createGUI(m_part); } } else { // if we couldn't find our Part, we exit since the Shell by // itself can't do anything useful KMessageBox::error(this, i18n("Unable to find kpdf part.")); kapp->quit(); // we return here, cause kapp->quit() only means "exit the // next time we enter the event loop... return; } connect( m_part, SIGNAL( rightClick() ),SLOT( slotRMBClick() ) ); readSettings(); } Shell::~Shell() { writeSettings(); } void Shell::openURL( const KURL & url ) { if ( m_part && m_part->openURL( url ) ) recent->addURL (url); } void Shell::readSettings() { recent->loadEntries( KGlobal::config() ); KGlobal::config()->setDesktopGroup(); bool fullScreen = KGlobal::config()->readBoolEntry( "FullScreen", false ); setFullScreen( fullScreen ); } void Shell::writeSettings() { saveMainWindowSettings(KGlobal::config(), "MainWindow"); recent->saveEntries( KGlobal::config() ); KGlobal::config()->setDesktopGroup(); KGlobal::config()->writeEntry( "FullScreen", m_fullScreenAction->isChecked()); KGlobal::config()->sync(); } void Shell::setupActions() { KStdAction::open(this, SLOT(fileOpen()), actionCollection()); recent = KStdAction::openRecent( this, SLOT( openURL( const KURL& ) ), actionCollection() ); - KStdAction::print(m_part, SLOT(print()), actionCollection()); + KStdAction::print(m_part, SLOT(slotPrint()), actionCollection()); KStdAction::quit(this, SLOT(slotQuit()), actionCollection()); setStandardToolBarMenuEnabled(true); m_showMenuBarAction = KStdAction::showMenubar( this, SLOT( slotShowMenubar() ), actionCollection(), "options_show_menubar" ); m_fullScreenAction = KStdAction::fullScreen( this, SLOT( slotUpdateFullScreen() ), actionCollection(), this ); m_popup = new KPopupMenu( this, "rmb popup" ); m_popup->insertTitle( i18n( "Full Screen Options" ) ); m_fullScreenAction->plug( m_popup ); m_popup->insertTitle( i18n( "Tools" ) ); m_showMenuBarAction->plug( m_popup ); } void Shell::saveProperties(KConfig* config) { // the 'config' object points to the session managed // config file. anything you write here will be available // later when this app is restored config->writePathEntry( "URL", m_part->url().url() ); } void Shell::slotShowMenubar() { if ( m_showMenuBarAction->isChecked() ) menuBar()->show(); else menuBar()->hide(); } void Shell::readProperties(KConfig* config) { // the 'config' object points to the session managed // config file. this function is automatically called whenever // the app is being restored. read in here whatever you wrote // in 'saveProperties' KURL url ( config->readPathEntry( "URL" ) ); if ( url.isValid() ) openURL( url ); } void Shell::fileOpen() { // this slot is called whenever the File->Open menu is selected, // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar // button is clicked KURL url = KFileDialog::getOpenURL( QString::null, "application/pdf" );//getOpenFileName(); if (!url.isEmpty()) openURL(url); } void Shell::applyNewToolbarConfig() { applyMainWindowSettings(KGlobal::config(), "MainWindow"); } void Shell::slotQuit() { kapp->closeAllWindows(); } void Shell::setFullScreen( bool useFullScreen ) { if( useFullScreen ) showFullScreen(); else showNormal(); } void Shell::slotUpdateFullScreen() { if( m_fullScreenAction->isChecked()) { menuBar()->hide(); toolBar()->hide(); //todo fixme showFullScreen(); #if 0 kapp->installEventFilter( m_fsFilter ); if ( m_gvpart->document()->isOpen() ) slotFitToPage(); #endif } else { //kapp->removeEventFilter( m_fsFilter ); menuBar()->show(); toolBar()->show(); showNormal(); } } void Shell::slotRMBClick() { m_popup->exec( QCursor::pos() ); } // vim:ts=2:sw=2:tw=78:et diff --git a/kpdf/page.cpp b/kpdf/page.cpp new file mode 100644 index 000000000..07b4cae0b --- /dev/null +++ b/kpdf/page.cpp @@ -0,0 +1,122 @@ +/*************************************************************************** + * 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 includes +#include +#include +#include + +// local includes +#include "TextOutputDev.h" +#include "page.h" + + +KPDFPage::KPDFPage( uint i, float w, float h ) + : m_number( i ), m_width( w ), m_height( h ), m_zoom( 1 ), + m_pixmap( 0 ), m_thumbnail( 0 ), m_text( 0 ), m_overlay( 0 ) +{ + printf( "hello %d\n", i ); +} + +KPDFPage::~KPDFPage() +{ + printf( "bye[%d] ", m_number ); + delete m_pixmap; + delete m_thumbnail; + delete m_text; + delete m_overlay; +} + +/** DRAWING **/ +void KPDFPage::drawPixmap( QPainter * p, const QRect & limits ) // MUTEXED +{ + threadLock.lock(); + + if ( m_pixmap ) + p->drawPixmap( limits.topLeft(), *m_pixmap, limits ); + else + p->fillRect( limits, Qt::blue ); + + threadLock.unlock(); +} + +void KPDFPage::drawThumbnail( QPainter * p ) // MUTEXED +{ + threadLock.lock(); + + if ( m_thumbnail ) + p->drawPixmap( 0,0, *m_thumbnail ); + else + p->fillRect( 10,10, 20,20, Qt::red ); + + threadLock.unlock(); +} + + +/** FIND **/ +bool KPDFPage::hasText( QString & text ) +{ + //FIXME + return text.isNull(); +} +/* +const QRect & KPDFPage::textPosition() +{ + //FIXME + return QRect(); +} +*/ + + +/** SLOTS **/ +void KPDFPage::slotSetZoom( float /*scale*/ ) +{ + +} + +void KPDFPage::slotSetContents( QPixmap * pix ) // MUTEXED +{ + if ( !pix ) + return; + + threadLock.lock(); + + delete m_pixmap; + m_pixmap = new QPixmap( pix->width() + 6, pix->height() + 6 ); + bitBlt( m_pixmap, 1,1, pix, 0,0, pix->width(),pix->height() ); + QPainter paint( m_pixmap ); + paint.drawRect( 0,0, pix->width()+1, pix->height()+1 ); + paint.end(); + //update page size (in pixels) + m_size = m_pixmap->size(); + + threadLock.unlock(); +} + +void KPDFPage::slotSetThumbnail( QPixmap * thumb ) // MUTEXED +{ + if ( !thumb ) + return; + + threadLock.lock(); + + delete m_thumbnail; + m_thumbnail = new QPixmap( *thumb ); + + threadLock.unlock(); +} + +void KPDFPage::slotSetOverlay() // MUTEXED +{ + threadLock.lock(); + //TODO this + threadLock.unlock(); +} + +#include "page.moc" diff --git a/kpdf/page.h b/kpdf/page.h new file mode 100644 index 000000000..37b81af6c --- /dev/null +++ b/kpdf/page.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * 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_PAGE_H_ +#define _KPDF_PAGE_H_ + +#include +#include +#include +#include "document.h" + +class QPixmap; +class QString; +class QRect; + +class TextOutputDev; +class PageOverlay{ /*fake temp*/ }; + +/** + * @short Collector for all the data belonging to a page. + * + * The Page class contains its pixmap, the thumbnail, a search page (a class + * used internally for searching data) the modifiers descriptors (for overlay + * graphics) and more. + * It provides accessor methods for all those operations too. + * + * Note: add stuff this class contains is destroyed automatically when the + * class is destroyed. + */ + +class KPDFPage : public QObject, public KPDFDocumentObserver +{ + Q_OBJECT + +public: + KPDFPage( uint number, float width, float height ); + ~KPDFPage(); + + // query methods + uint number() const { return m_number; } + float width() const { return m_width; } + float height() const { return m_height; } + float ratio() const { return m_height / m_width; } + + float currentZoom() const { return m_zoom; } + const QSize & currentSize() const { return m_size; } + void drawPixmap( QPainter * p, const QRect & rect ); + void drawThumbnail( QPainter * p ); + + // find related methods + bool hasText( QString & text ); + //const QRect & textPosition(); + +signals: + void changed( KPDFPage * thisPage ); + +private slots: + void slotSetZoom( float scale ); + void slotSetContents( QPixmap * ); + void slotSetThumbnail( QPixmap * ); + void slotSetOverlay( /*..DOMdescription..*/ ); + +private: + QMutex threadLock; + + uint m_number; + float m_width, m_height; + float m_zoom; + QSize m_size; + QPixmap * m_pixmap; + QPixmap * m_thumbnail; + TextOutputDev * m_text; + PageOverlay * m_overlay; +}; + +#endif diff --git a/kpdf/thumbnaillist.cpp b/kpdf/thumbnaillist.cpp index 7ac5fb08c..2df8ba457 100644 --- a/kpdf/thumbnaillist.cpp +++ b/kpdf/thumbnaillist.cpp @@ -1,177 +1,177 @@ /*************************************************************************** * 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 "PDFDoc.h" #include "thumbnailgenerator.h" #include "thumbnaillist.h" #include "thumbnail.h" ThumbnailList::ThumbnailList(QWidget *parent, QMutex *docMutex) : QTable(parent), m_tg(0), m_doc(0), m_docMutex(docMutex) { setNumCols(1); setLeftMargin(0); setTopMargin(0); setHScrollBarMode(QScrollView::AlwaysOff); m_selected = 0; connect(this, SIGNAL(pressed(int, int, int, const QPoint&)), this, SLOT(emitClicked(int))); connect(this, SIGNAL(currentChanged(int, int)), this, SLOT(emitClicked(int))); connect(this, SIGNAL(currentChanged(int, int)), this, SLOT(changeSelected(int))); } ThumbnailList::~ThumbnailList() { if (m_tg) { m_tg->wait(); delete m_tg; } } void ThumbnailList::setCurrentThumbnail(int i) { setCurrentCell(i-1, 0); changeSelected(i-1); } void ThumbnailList::changeSelected(int i) { Thumbnail *t; t = dynamic_cast(cellWidget(m_selected, 0)); if (t) t -> setSelected(false); m_selected = i; t = dynamic_cast(cellWidget(m_selected, 0)); if (t) t -> setSelected(true); } 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; } void ThumbnailList::setPages(int i, double ar) { Thumbnail *t; m_ar = ar; setNumRows(i); for(int j=1; j <= i; j++) { t = new Thumbnail(this, QString::number(j), viewport()->paletteBackgroundColor(), (int)(visibleWidth()*ar), visibleWidth()); setCellWidget(j-1, 0, t); setRowHeight(j-1, t->sizeHint().height()); } m_heightLimit = 0; } void ThumbnailList::setThumbnail(int i, const QImage *thumbnail) { Thumbnail *t; t = dynamic_cast(cellWidget(i-1, 0)); t->setImage(thumbnail); } void ThumbnailList::viewportResizeEvent(QResizeEvent *) { // that if are here to avoid recursive resizing of death // where the user makes the window smaller, that makes appear // the vertical scrollbar, that makes thumbnails smaller, and // while they get smaller the vertical scrollbar is not needed // and ... // ... it also works for when the user makes the window larger // and then the scrollbar disappears but that makes thumbnails // larger and then scrollbar reappears and ... Thumbnail *t; if (numRows() == 0) return; t = dynamic_cast(cellWidget(0, 0)); if (size().height() <= m_heightLimit) { if (t->getImageHeight() > (int)(visibleWidth()*m_ar)) { setColumnWidth(0, visibleWidth()); resizeThumbnails(); } } else { if (visibleWidth() != columnWidth(0)) { setColumnWidth(0, visibleWidth()); resizeThumbnails(); if (size().height() > m_heightLimit && verticalScrollBar() -> isVisible()) { m_heightLimit = (int) ceil(numRows() * ((visibleWidth() + verticalScrollBar() -> width()) * m_ar + t -> labelSizeHintHeight())); } - } - } + } + } } void ThumbnailList::resizeThumbnails() { Thumbnail *t; for(int i = 0; i < numRows(); ++i) { t = dynamic_cast(cellWidget(i, 0)); t->setImageSize((int)(visibleWidth()*m_ar), visibleWidth()); setRowHeight(i, (int)(visibleWidth()*m_ar) + t->labelSizeHintHeight()); - } + } } void ThumbnailList::emitClicked(int i) { emit clicked(i+1); } #include "thumbnaillist.moc" diff --git a/kpdf/thumbnaillist.h b/kpdf/thumbnaillist.h index 4e927f0c3..f20ca37c6 100644 --- a/kpdf/thumbnaillist.h +++ b/kpdf/thumbnaillist.h @@ -1,62 +1,76 @@ /*************************************************************************** * 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. * ***************************************************************************/ #ifndef THUMBNAILLIST_H #define THUMBNAILLIST_H #include +#include "document.h" class QImage; class PDFDoc; class ThumbnailGenerator; -class ThumbnailList : public QTable +class ThumbnailList : public QTable, public KPDFDocumentObserver { Q_OBJECT public: ThumbnailList(QWidget *parent, QMutex *docMutex); ~ThumbnailList(); - + + // inherited as KPDFDocumentObserver + void pageSetup( const QValueList & pages ) + { + // TODO use a qvaluelist to pass aspect ratio? + // TODO move it the thumbnail list? + setPages( pages.count(), 2 ); + //generateThumbnails(d->pdfdoc); + } + void pageSetCurrent( int /*pageNumber*/, float /*position*/ ) + { + //setCurrentThumbnail(m_currentPage); + } + void setCurrentThumbnail(int i); void setPages(int i, double ar); 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); protected: void viewportResizeEvent(QResizeEvent *); private: void generateNextThumbnail(); void resizeThumbnails(); void setThumbnail(int i, const QImage *thumbnail); double m_ar; int m_selected; int m_heightLimit; int m_nextThumbnail; ThumbnailGenerator *m_tg; PDFDoc *m_doc; QMutex *m_docMutex; bool m_ignoreNext; }; #endif