Commit e548f404 authored by Enrico Ros's avatar Enrico Ros

Optimized syncronous thumbnails/pixmap loaders. Moved some actions from the

part to the two sub-widgets. Cleanups and commented stuff. I love comments.

svn path=/branches/kpdf_experiments/kdegraphics/kpdf/; revision=345701
parent 712dd1e8
......@@ -34,7 +34,9 @@ public:
// document related
QMutex docLock;
PDFDoc * pdfdoc;
QOutputDev * splashOutputDevice;
int currentPage;
float currentPosition;
QValueVector< KPDFPage* > pages;
// observers related (note: won't delete oservers)
......@@ -54,11 +56,16 @@ KPDFDocument::KPDFDocument()
d = new KPDFDocumentPrivate;
d->pdfdoc = 0;
d->currentPage = -1;
d->currentPosition = 0;
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8( 0xff, 0xff, 0xff );
d->splashOutputDevice = new QOutputDev( paperColor );
}
KPDFDocument::~KPDFDocument()
{
close();
delete d->splashOutputDevice;
delete d;
}
......@@ -72,10 +79,10 @@ bool KPDFDocument::openFile( const QString & docFile )
GString *filename = new GString( QFile::encodeName( docFile ) );
delete d->pdfdoc;
deletePages();
d->pdfdoc = new PDFDoc( filename, 0, 0 );
if ( !d->pdfdoc->isOk() || d->pdfdoc->getNumPages() < 1 )
deletePages();
if ( !d->pdfdoc->isOk() )
{
delete d->pdfdoc;
d->pdfdoc = 0;
......@@ -85,17 +92,20 @@ bool KPDFDocument::openFile( const QString & docFile )
// clear xpdf errors
errors::clear();
// build Pages
d->currentPage = -1;
// initialize output device for rendering current pdf
d->splashOutputDevice->startDoc( d->pdfdoc->getXRef() );
// build Pages (currentPage was set -1 by deletePages)
uint pageCount = d->pdfdoc->getNumPages();
d->pages.resize( pageCount );
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 = NONE; TODO
sendFilteredPageList();
slotSetCurrentPage( 0 );
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
sendFilteredPageList();
slotSetCurrentPage( 0 );
}
return true;
}
......@@ -142,9 +152,10 @@ void KPDFDocument::slotSetCurrentPage( int page )
void KPDFDocument::slotSetCurrentPagePosition( int page, float position )
{
if ( page == d->currentPage ) //TODO check position
if ( page == d->currentPage && position == d->currentPosition )
return;
d->currentPage = page;
d->currentPosition = position;
foreachObserver( pageSetCurrent( page, position ) );
pageChanged();
}
......@@ -230,57 +241,76 @@ void KPDFDocument::slotGoToLink( /* QString anchor */ )
{
}
void KPDFDocument::slotSetZoom( float /*zoom*/ )
{
}
void KPDFDocument::slotChangeZoom( float /*offset*/ )
{
}
void KPDFDocument::addObserver( KPDFDocumentObserver * pObserver )
{
d->observers.push_back( pObserver );
}
void KPDFDocument::requestPixmap( uint /*page*/, int /*width*/, int /*height*/ )
void KPDFDocument::requestPixmap( uint page, int width, int height, bool syn )
{
//think at this.. Syncronous or Asyncronous that's the problem! (shakespeare)
KPDFPage * kp = d->pages[page];
if ( !d->pdfdoc || !kp || kp->width() < 1 || kp->height() < 1 )
return;
if ( syn )
{
// in-place Pixmap generation for syncronous requests
if ( !kp->hasPixmap( 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();
d->docLock.lock();
d->pdfdoc->displayPage( d->splashOutputDevice, page + 1, fakeDpiX, fakeDpiY, 0, true, false );
d->docLock.unlock();
// it may happen (in fact it doesn't) that we need rescaling
if ( d->splashOutputDevice->getImage().size() != QSize( width, height ) )
kp->setPixmap( d->splashOutputDevice->getImage().smoothScale( width, height ) );
else
kp->setPixmap( d->splashOutputDevice->getImage() );
foreachObserver( notifyPixmapChanged( page ) );
}
}
else
{
//TODO asyncronous events queuing
}
}
void KPDFDocument::requestThumbnail( uint page, int width, int height )
void KPDFDocument::requestThumbnail( uint page, int width, int height, bool syn )
{
// TODO FIXME BEGIN :: TEMP CODE. ONLY A TEST. quick in-place thumbnail gen
KPDFPage * kp = d->pages[page];
if ( !kp )
if ( !d->pdfdoc || !kp || kp->width() < 1 || kp->height() < 1 )
return;
if ( !kp->hasThumbnail( width, height ) && d->pdfdoc && kp->width() > 0 && kp->height() > 0 )
if ( /*syn*/ TRUE )
{
// make thumbnail pixmap
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8( 0xff, 0xff, 0xff );
QOutputDev odev( paperColor );
odev.startDoc( d->pdfdoc->getXRef() );
double fakeDpiX = width * 72.0 / kp->width(),
fakeDpiY = height * 72.0 / kp->height();
d->docLock.lock();
d->pdfdoc->displayPage( &odev, page + 1, fakeDpiX, fakeDpiY, 0, true, false );
d->docLock.unlock();
// It can happen (but with zero+ probability :-) that the output
// image doesn't have the right size. In that case scale it.
if ( odev.getImage().size() != QSize( width, height ) )
// in-place Thumbnail generation for syncronous requests
if ( !kp->hasThumbnail( width, height ) )
{
QImage scaled( odev.getImage().smoothScale( width, height ) );
kp->setThumbnail( scaled );
// 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();
d->docLock.lock();
d->pdfdoc->displayPage( d->splashOutputDevice, page + 1, fakeDpiX, fakeDpiY, 0, true, false );
d->docLock.unlock();
// it may happen (in fact it doesn't) that we need rescaling
if ( d->splashOutputDevice->getImage().size() != QSize( width, height ) )
kp->setThumbnail( d->splashOutputDevice->getImage().smoothScale( width, height ) );
else
kp->setThumbnail( d->splashOutputDevice->getImage() );
foreachObserver( notifyThumbnailChanged( page ) );
}
else
kp->setThumbnail( odev.getImage() );
foreachObserver( notifyThumbnailChanged( page ) );
}
// TODO FIXME END :: TEMP CODE. ONLY A TEST.
else
{
//TODO asyncronous events queuing
}
}
......
......@@ -63,8 +63,8 @@ public:
// observers related methods
void addObserver( KPDFDocumentObserver * pObserver );
void requestPixmap( uint page, int width, int height );
void requestThumbnail( uint page, int width, int height );
void requestPixmap( uint page, int width, int height, bool syncronous = false );
void requestThumbnail( uint page, int width, int height, bool syncronous = false );
public slots:
// document commands via slots
......@@ -72,13 +72,10 @@ public slots:
void slotSetCurrentPagePosition( int page, float position );
void slotFind( bool nextMatch, const QString & text = "" );
void slotGoToLink( /* QString anchor */ );
void slotSetZoom( float zoom );
void slotChangeZoom( float offset );
signals:
// notify changes via signals
void pageChanged();
void zoomChanged( float newZoom );
private:
void sendFilteredPageList();
......
......@@ -20,6 +20,11 @@
#include <kglobalsettings.h>
#include <kurldrag.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <klocale.h>
#include <kconfigbase.h>
#include "PDFDoc.h"
#include "kpdf_pagewidget.h"
......@@ -289,7 +294,7 @@ void PageWidget::keyPressEvent( QKeyEvent* e )
if ( m_doc )
{
// Pixels per point when the zoomFactor is 1.
const float ppp = (float)QPaintDevice::x11AppDpiX() * 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, ppp, 0, true, true);
......@@ -378,6 +383,96 @@ void PageWidget::keyPressEvent( QKeyEvent* e )
return b;
}
void PageWidget::setupActions( KActionCollection * ac, KConfigGroup * config )
{
// 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( this, SLOT(slotZoomIn()), ac, "zoom_in" );
KStdAction::zoomOut( this, SLOT(slotZoomOut()), 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 ) ) );
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_showScrollBars->setChecked( config->readBoolEntry( "ShowScrollBars", true ) );
slotToggleScrollBars( m_showScrollBars->isChecked() );
}
void PageWidget::saveSettings( KConfigGroup * config )
{
config->writeEntry( "ShowScrollBars", m_showScrollBars->isChecked() );
}
void PageWidget::slotZoom( const QString & nz )
{
QString z = nz;
z.remove( z.find( '%' ), 1 );
bool isNumber = true;
double zoom = KGlobal::locale()->readNumber( z, &isNumber ) / 100;
zoom = 0;//CUT WARNINGS (but remove me:-)
/* if ( isNumber )
document->slotSetZoom( zoom );*/
}
void PageWidget::slotZoomIn()
{
// document->slotChangeZoom( 0.1 );
}
void PageWidget::slotZoomOut()
{
// document->slotChangeZoom( -0.1 );
}
void PageWidget::slotFitToWidthToggled( bool /*fit*/ )
{
/*
m_zoomMode = m_fitToWidth->isChecked() ? FitWidth : FixedFactor;
displayPage(m_currentPage);
*/
}
void PageWidget::slotToggleScrollBars( bool show )
{
enableScrollBars( show );
}
void PageWidget::slotSetZoom( float /*zoom*/ )
{
}
void PageWidget::slotChangeZoom( float /*offset*/ )
{
}
}
/** TO BE IMPORTED
......
......@@ -21,8 +21,8 @@
#include "CharTypes.h"
class KURL;
class QWidget;
class KActionCollection;
class KConfigGroup;
class LinkAction;
class PDFDoc;
......@@ -45,13 +45,16 @@ namespace KPDF
PageWidget(QWidget *parent, KPDFDocument *document);
~PageWidget();
void setPixelsPerPoint(float);
/* void setLinks(); */
// create actions that interact with this widget
void setupActions( KActionCollection * collection, KConfigGroup * config );
void saveSettings( KConfigGroup * config );
// inherited from KPDFDocumentObserver
void pageSetup( const QValueList<int> & pages );
void pageSetCurrent( int pageNumber, float position );
void setPixelsPerPoint(float);
/* void setLinks(); */
void enableScrollBars( bool b );
/**
......@@ -72,7 +75,23 @@ namespace KPDF
void scrollTop();
bool readUp();
bool readDown();
signals:
void slotZoom( const QString& );
void slotZoomIn();
void slotZoomOut();
void slotFitToWidthToggled( bool );
void slotToggleScrollBars( bool );
void slotSetZoom( float zoom );
void slotChangeZoom( float offset );
private:
KToggleAction *m_showScrollBars;
KSelectAction *m_zoomTo;
KToggleAction *m_fitToWidth;
signals:
void zoomChanged( float newZoom );
void linkClicked(LinkAction*);
void ReadUp();
void ReadDown();
......
......@@ -84,22 +84,20 @@ Part::Part(QWidget *parentWidget, const char *widgetName,
connect( document, SIGNAL( pageChanged() ), this, SLOT( updateActions() ) );
// build widgets
QSplitter *split = new QSplitter( parentWidget, widgetName );
split->setOpaqueResize( true );
m_splitter = new QSplitter( parentWidget, widgetName );
m_splitter->setOpaqueResize( true );
setWidget( m_splitter );
m_thumbnailList = new ThumbnailList( split, document );
m_thumbnailList = new ThumbnailList( m_splitter, document );
m_thumbnailList->setMaximumWidth( 125 );
m_thumbnailList->setMinimumWidth( 50 );
document->addObserver( m_thumbnailList );
m_pageWidget = new KPDF::PageWidget( split, document );
m_pageWidget = new KPDF::PageWidget( m_splitter, document );
connect( m_pageWidget, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURL( const KURL & )));
//connect(m _pageWidget, SIGNAL( rightClick() ), this, SIGNAL( rightClick() ));
document->addObserver( m_pageWidget );
//TODO split->setSizes( QValueList<int> list ); loaded from config file (last setup)
setWidget(split);
// ACTIONS
KActionCollection * ac = actionCollection();
......@@ -112,75 +110,44 @@ Part::Part(QWidget *parentWidget, const char *widgetName,
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 = KStdAction::firstPage( this, SLOT( slotGotoFirst() ), 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 = KStdAction::lastPage( this, SLOT( slotGotoLast() ), 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");
// Find and other 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 = 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::saveAs( this, SLOT( slotSaveFileAs() ), ac, "save" );
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 ) ) );
// attach the actions of the 2 children widgets too
KConfigGroup settings( KPDFPartFactory::instance()->config(), "General" );
m_pageWidget->setupActions( ac, &settings );
m_thumbnailList->setupActions( ac, &settings );
KStdAction::saveAs(this, SLOT(slotSaveFileAs()), ac, "save");
// local settings
m_splitter->setSizes( settings.readIntListEntry( "SplitterSizes" ) );
// set our XML-UI resource file
setXMLFile("kpdf_part.rc");
readSettings();
updateActions();
}
Part::~Part()
{
KConfigGroup settings( KPDFPartFactory::instance()->config(), "General" );
m_pageWidget->saveSettings( &settings );
m_thumbnailList->saveSettings( &settings );
settings.writeEntry( "SplitterSizes", m_splitter->sizes() );
settings.sync();
delete document;
writeSettings();
if ( --m_count == 0 )
delete globalParams;
}
......@@ -198,8 +165,8 @@ KAboutData* Part::createAboutData()
bool Part::openFile()
{
bool ok = document->openFile( m_file );
m_find->setEnabled(ok);
m_findNext->setEnabled(ok);
m_find->setEnabled( ok );
m_findNext->setEnabled( ok );
return ok;
}
......@@ -229,23 +196,6 @@ void Part::updateActions()
}
}
void Part::readSettings()
{
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::writeSettings()
{
KConfigGroup general( KPDFPartFactory::instance()->config(), "General" );
general.writeEntry( "ShowScrollBars", m_showScrollBars->isChecked() );
general.writeEntry( "ShowPageList", m_showPageList->isChecked() );
general.sync();
}
//BEGIN go to page dialog
class KPDFGotoPageDialog : public KDialogBase
{
......@@ -295,12 +245,12 @@ void Part::slotNextPage()
document->slotSetCurrentPage( document->currentPage() + 1 );
}
void Part::slotGotoStart()
void Part::slotGotoFirst()
{
document->slotSetCurrentPage( 0 );
}
void Part::slotGotoEnd()
void Part::slotGotoLast()
{
document->slotSetCurrentPage( document->pages() - 1 );
}
......@@ -317,45 +267,6 @@ void Part::slotFindNext()
document->slotFind( true );
}
void Part::slotZoom( const QString & nz )
{
QString z = nz;
z.remove( z.find( '%' ), 1 );
bool isNumber = true;
double zoom = KGlobal::locale()->readNumber( z, &isNumber ) / 100;
if ( isNumber )
document->slotSetZoom( zoom );
}
void Part::slotZoomIn()
{
document->slotChangeZoom( 0.1 );
}
void Part::slotZoomOut()
{
document->slotChangeZoom( -0.1 );
}
void Part::slotFitToWidthToggled( bool /*fit*/ )
{
/*
m_zoomMode = m_fitToWidth->isChecked() ? FitWidth : FixedFactor;
displayPage(m_currentPage);
*/
}
void Part::slotToggleScrollBars( bool show )
{
m_pageWidget->enableScrollBars( show );
}
void Part::slotToggleThumbnails( bool show )
{
m_thumbnailList->setShown( show );
}
void Part::slotSaveFileAs()
{
KURL saveURL = KFileDialog::getSaveURL(
......
......@@ -20,21 +20,19 @@
#include <kparts/part.h>
class QWidget;
class QSplitter;
class KAboutData;
class KAction;
class KPrinter;
class KURL;
class KAction;
class KToggleAction;
class KSelectAction;
class KAboutData;
class KPrinter;
class LinkAction;
class LinkDest;
class XOutputDev;
class ThumbnailList;
class PDFPartView;
class KPDFDocument;
namespace KPDF
......@@ -77,8 +75,6 @@ namespace KPDF
// reimplemented from KParts::ReadOnlyPart
virtual bool openFile();
void readSettings();
void writeSettings();
void updateAction();
void doPrint( KPrinter& printer );
......@@ -87,19 +83,13 @@ namespace KPDF
void slotGoToPage();
void slotPreviousPage();
void slotNextPage();
void slotGotoStart();
void slotGotoEnd();
void slotGotoFirst();
void slotGotoLast();
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 slotPrintPreview();
// can be connected to widget elements
void updateActions();
public slots:
......@@ -111,6 +101,7 @@ namespace KPDF
KPDFDocument * document;
// main widgets
QSplitter *m_splitter;
ThumbnailList *m_thumbnailList;
PageWidget *m_pageWidget;
......@@ -123,10 +114,6 @@ namespace KPDF
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;
};
......
......@@ -77,15 +77,27 @@ bool KPDFPage::hasThumbnail( int width, int height ) const
return m_thumbnail ? ( m_thumbnail->width() == width && m_thumbnail->height() == height ) : false;
}