Commit 69bb375c authored by Enrico Ros's avatar Enrico Ros

Thumbnail and ThumbnailList classes completed. Optimized a lot! Too fast

now.. thre will be room for eye-candy in the future :-P. Drawing is scaled
via a qpainter xForm while resizing and a regeneration is performed
asyncronously when thumbnaillist's resizing is done.

svn path=/branches/kpdf_experiments/kdegraphics/kpdf/; revision=345459
parent daa42b1d
Personal Albert's list
-> make links functional
-> improve thumbnail generation to make it non-gui blocking
More items
-> merge lots of kpdf_part and part (centralview) code (to simplify/clenup)
-> previews sorted by visible areas (prioritize items where the scrollbar is)
-> maybe: use local instead of X memory for thumbnails (..)
-> screen editing: framework
-> screen editing: tools
Porting / In progress
-> implementing Document / Page using AACid's thread as the generation thread
-> improve thumbnail generation to make it non-gui blocking
-> multiple pages per view
-> centering pages in the view
-> outline bottom and right edges (of pages)
Done
-> merge lots of kpdf_part and part (centralview) code (to simplify/clenup)
-> maybe: use local instead of X memory for thumbnails (..)
-> previews sorted by visible areas (prioritize items where the scrollbar is)
......@@ -50,18 +50,41 @@ namespace KPDF
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::pageSetup( const QValueList<int> & /*pages*/ )
{
/*
m_doc = doc;
m_outputdev -> startDoc(doc->getXRef());
m_currentPage = 1;
updatePixmap();
*/
}
void PageWidget::pageSetCurrent( int /*pageNumber*/, float /*position*/ )
{
/*
// 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 = pageNumber;
} else {
m_currentPage = 0;
}
updatePixmap();
mutex.unlock();
*/
}
void
PageWidget::setPixelsPerPoint(float ppp)
......@@ -126,7 +149,7 @@ namespace KPDF
}
void PageWidget::drawContents ( QPainter *p, int clipx, int clipy, int clipw, int cliph )
{
{return;
QImage im;
QColor bc(KGlobalSettings::calculateAlternateBackgroundColor(KGlobalSettings::baseColor()));
if (m_outputdev)
......@@ -181,50 +204,12 @@ namespace KPDF
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() );
......@@ -235,39 +220,36 @@ namespace KPDF
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();
}
void PageWidget::keyPressEvent( QKeyEvent* e )
{
switch ( e->key() ) {
case Key_Up:
if ( atTop() )
emit ReadUp();
else
verticalScrollBar()->subtractLine();
break;
case Key_Down:
if ( atBottom() )
emit ReadDown();
else
verticalScrollBar()->addLine();
break;
case Key_Left:
horizontalScrollBar()->subtractLine();
break;
case Key_Right:
horizontalScrollBar()->addLine();
break;
case Key_Space:
if( e->state() != ShiftButton )
emit spacePressed();
default:
e->ignore();
return;
}
e->accept();
}
bool PageWidget::atTop() const
{
......
......@@ -44,21 +44,15 @@ namespace KPDF
public:
PageWidget(QWidget *parent, KPDFDocument *document);
~PageWidget();
void setPDFDocument(PDFDoc*);
void setPixelsPerPoint(float);
/* void setLinks(); */
// inherited from KPDFDocumentObserver
void pageSetup( const QValueList<int> & /*pages*/ )
{/*
m_outputDev->setPDFDocument(d->pdfdoc);
*/}
void pageSetCurrent( int /*pageNumber*/, float /*position*/ )
{
//m_pageWidget->setPage(m_currentPage);
}
void setPage(int pagenum);
void pageSetup( const QValueList<int> & pages );
void pageSetCurrent( int pageNumber, float position );
void enableScrollBars( bool b );
/**
* Return true if the top resp. bottom of the page is visible.
......@@ -74,10 +68,6 @@ namespace KPDF
void zoomOut();
void updatePixmap();
void scrollUp();
void scrollDown();
void scrollRight();
void scrollLeft();
void scrollBottom();
void scrollTop();
bool readUp();
......
......@@ -69,7 +69,9 @@ Part::Part(QWidget *parentWidget, const char *widgetName,
// create browser extension (for printing when embedded into browser)
new BrowserExtension(this);
// xpdf 'extern' global class (m_count is a static instance counter) TODO check for wasted creation
// xpdf 'extern' global class (m_count is a static instance counter)
//if ( m_count ) TODO check if we need to insert these lines..
// delete globalParams;
globalParams = new GlobalParams("");
globalParams->setupBaseFonts(NULL);
m_count++;
......
......@@ -7,7 +7,8 @@
* (at your option) any later version. *
***************************************************************************/
// qt includes
// qt includes
#include <qapplication.h>
#include <qpixmap.h>
#include <qstring.h>
#include <qpainter.h>
......@@ -16,18 +17,21 @@
#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 ),
#include <qimage.h>
KPDFPage::KPDFPage( uint page, float w, float h )
: m_number( page ), m_width( w ), m_height( h ), m_zoom( 1 ),
m_pixmap( 0 ), m_thumbnail( 0 ), m_text( 0 ), m_overlay( 0 )
{
printf( "hello %d ", i );
m_thumbnail = new QPixmap( "/a.png", "PNG" );
/* m_thumbnail = new QPixmap( "/a.png", "PNG" );
QImage im = m_thumbnail->convertToImage();
im = im.smoothScale(100,100);
im.setAlphaBuffer( false );
m_thumbnail->convertFromImage(im);
*/
}
KPDFPage::~KPDFPage()
{
printf( "bye[%d] ", m_number );
delete m_pixmap;
delete m_thumbnail;
delete m_text;
......@@ -47,15 +51,21 @@ void KPDFPage::drawPixmap( QPainter * p, const QRect & limits ) const // MUTEXE
//threadLock.unlock();
}
void KPDFPage::drawThumbnail( QPainter * p, const QRect & limits ) const // MUTEXED
void KPDFPage::drawThumbnail( QPainter * p, const QRect & limits, int width, int height ) const // OK
{
//threadLock.lock();
if ( m_thumbnail )
p->drawPixmap( limits.topLeft(), *m_thumbnail, limits );
{
if ( m_thumbnail->width() == width && m_thumbnail->height() == height )
p->drawPixmap( limits.topLeft(), *m_thumbnail, limits );
else
{
p->scale( width / (double)m_thumbnail->width(), height / (double)m_thumbnail->height() );
p->drawPixmap( 0,0, *m_thumbnail, 0,0, m_thumbnail->width(), m_thumbnail->height() );
}
}
else
p->fillRect( limits, Qt::red );
p->fillRect( limits, QApplication::palette().active().base() );
//threadLock.unlock();
}
......
......@@ -13,7 +13,6 @@
#include <qobject.h>
#include <qsize.h>
#include <qmutex.h>
#include "document.h"
class QPixmap;
class QString;
......@@ -34,7 +33,7 @@ class PageOverlay{ /*fake temp*/ };
* class is destroyed.
*/
class KPDFPage : public QObject, public KPDFDocumentObserver
class KPDFPage : public QObject
{
Q_OBJECT
......@@ -50,7 +49,7 @@ public:
// rendering
void drawPixmap( QPainter * p, const QRect & rect ) const;
void drawThumbnail( QPainter * p, const QRect & rect ) const;
void drawThumbnail( QPainter * p, const QRect & rect, int width, int height ) const;
float currentZoom() const { return m_zoom; }
const QSize & currentSize() const { return m_size; }
......
......@@ -7,50 +7,83 @@
* (at your option) any later version. *
***************************************************************************/
#include <qapplication.h>
#include <qimage.h>
#include <qlabel.h>
#include <qpixmap.h>
#include <qpainter.h>
#include "thumbnail.h"
#include "page.h"
Thumbnail::Thumbnail(QWidget *parent, const QColor &color, const KPDFPage *page) : QVBox(parent), m_page(page), m_backgroundColor(color)
Thumbnail::Thumbnail( QWidget *parent, const KPDFPage *page )
: QWidget( parent ), m_page( page ), m_previewWidth( 0 ), m_previewHeight( 0 )
{
m_thumbnailW = new QWidget(this);
m_thumbnailW->setEraseColor(Qt::gray);
m_label = new QLabel(QString::number(page->number()+1), this);
m_label->setAlignment(AlignCenter);
setPaletteBackgroundColor(m_backgroundColor);
m_label = new QLabel( QString::number( page->number() + 1 ), this );
m_label->setAlignment( AlignCenter );
setPaletteBackgroundColor( palette().active().base() );
}
int Thumbnail::pageNumber()
//BEGIN commands
int Thumbnail::setThumbnailWidth( int width )
{
return m_page->number();
// compute and update drawable area dimensions
// note: 3 pixels are left (in each dimension) for page decorations
m_previewWidth = width - 3;
//TODO albert: check page rotation for aspect ratio
m_previewHeight = (int)(m_page->ratio() * width);
// reposition label at bottom
int labelHeight = m_label->sizeHint().height();
m_label->setGeometry( 0, m_previewHeight + 3, width, labelHeight );
// resize the widget
int totalHeight = m_previewHeight + 3 + labelHeight;
resize( width, totalHeight );
// return this->height plus a little (4px) margin to the next page
return totalHeight + 4;
}
void Thumbnail::setSelected( bool selected )
{
// alternate 'base' or 'hilight' colors to represent selection
if (selected) m_label->setPaletteBackgroundColor( palette().active().highlight() );
else m_label->setPaletteBackgroundColor( palette().active().base() );
}
//END commands
void Thumbnail::setImage(const QImage *thumbnail)
//BEGIN query methods
int Thumbnail::pageNumber() const
{
// TODO i am almost sure this can be done inside the thumbnailgenerator thread
m_original = thumbnail->smoothScale(m_thumbnailW->size());
m_thumbnailW->setPaletteBackgroundPixmap(m_original);
return m_page->number();
}
int Thumbnail::setThumbnailWidth(int width)
int Thumbnail::previewWidth() const
{
int height = (int)(m_page->ratio() * width);
m_thumbnailW->setFixedHeight(height);
m_thumbnailW->setFixedWidth(width);
height += m_label->sizeHint().height();
resize( width, height );
return height;
return m_previewWidth;
}
void Thumbnail::setSelected(bool selected)
int Thumbnail::previewHeight() const
{
if (selected) setPaletteBackgroundColor(QApplication::palette().active().highlight());
else setPaletteBackgroundColor(m_backgroundColor);
return m_previewHeight;
}
//END query methods
void Thumbnail::paintEvent( QPaintEvent * e )
{
QRect clipRect = e->rect();
QPainter p( this );
// draw page outline
p.setPen( Qt::black );
p.drawRect( 0, 0, m_previewWidth + 2, m_previewHeight + 2 );
p.setPen( Qt::gray );
p.drawLine( 4, m_previewHeight + 2, m_previewWidth + 2, m_previewHeight + 2 );
p.drawLine( m_previewWidth + 2, 4, m_previewWidth + 2, m_previewHeight + 2 );
// draw the pixmap
p.translate( 1, 1 );
clipRect.moveBy( -1, -1 );
clipRect = clipRect.intersect( QRect( 0, 0, m_previewWidth, m_previewHeight ) );
m_page->drawThumbnail( &p, clipRect, m_previewWidth, m_previewHeight );
#include "thumbnail.moc"
p.end();
}
......@@ -10,30 +10,33 @@
#ifndef THUMBNAIL_H
#define THUMBNAIL_H
#include <qcolor.h>
#include <qimage.h>
#include <qvbox.h>
#include <qwidget.h>
class QLabel;
class KPDFPage;
class Thumbnail : public QVBox
class Thumbnail : public QWidget
{
Q_OBJECT
public:
Thumbnail(QWidget *parent, const QColor &color, const KPDFPage *page);
Thumbnail(QWidget *parent, const KPDFPage *page);
int pageNumber();
void setImage(const QImage *thumbnail);
int setThumbnailWidth( int w );
// resize / select commands
int setThumbnailWidth(int width);
void setSelected(bool selected);
// query methods
int pageNumber() const;
int previewWidth() const;
int previewHeight() const;
protected:
void paintEvent(QPaintEvent *);
private:
QWidget *m_thumbnailW;
QLabel *m_label;
const KPDFPage *m_page;
QColor m_backgroundColor;
QImage m_original;
uint m_previewWidth;
uint m_previewHeight;
};
#endif
......@@ -30,6 +30,7 @@ ThumbnailList::ThumbnailList(QWidget *parent, KPDFDocument *document)
// set contents background to the 'base' color
viewport()->setPaletteBackgroundColor( palette().active().base() );
setFrameStyle( StyledPanel | Raised );
connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestThumbnails(int, int)) );
}
......@@ -58,7 +59,7 @@ void ThumbnailList::pageSetup( const QValueList<int> & pages )
QValueList<int>::const_iterator pageEnd = pages.end();
for (; pageIt != pageEnd ; ++pageIt)
{
t = new Thumbnail( viewport(), viewport()->paletteBackgroundColor(), m_document->page(*pageIt) );
t = new Thumbnail( viewport(), m_document->page(*pageIt) );
// add to the scrollview
addChild( t, 0, totalHeight );
// add to the internal queue
......@@ -117,21 +118,32 @@ void ThumbnailList::notifyThumbnailChanged( int pageNumber )
void ThumbnailList::keyPressEvent( QKeyEvent * keyEvent )
{
if ( thumbnails.count() < 1 )
return;
return keyEvent->ignore();
if ( keyEvent->key() == Key_Up )
{
if ( !m_selected )
m_document->slotSetCurrentPage( 0 );
else if ( vectorIndex > 0 )
m_document->slotSetCurrentPage( thumbnails[ --vectorIndex ]->pageNumber() );
m_document->slotSetCurrentPage( thumbnails[ vectorIndex - 1 ]->pageNumber() );
else
return keyEvent->ignore();
}
else if ( keyEvent->key() == Key_Down )
{
if ( !m_selected )
m_document->slotSetCurrentPage( 0 );
else if ( vectorIndex < (int)thumbnails.count() - 1 )
m_document->slotSetCurrentPage( thumbnails[ ++vectorIndex ]->pageNumber() );
m_document->slotSetCurrentPage( thumbnails[ vectorIndex + 1 ]->pageNumber() );
else
return keyEvent->ignore();
}
else if ( keyEvent->key() == Key_Home )
m_document->slotSetCurrentPage( thumbnails[ 0 ]->pageNumber() );
else if ( keyEvent->key() == Key_End )
m_document->slotSetCurrentPage( thumbnails[ thumbnails.count() - 1 ]->pageNumber() );
else
return keyEvent->ignore();
keyEvent->accept();
}
void ThumbnailList::contentsMousePressEvent( QMouseEvent * e )
......@@ -159,6 +171,7 @@ void ThumbnailList::viewportResizeEvent(QResizeEvent *e)
// right place and recalculate the contents area
if ( e->size().width() != e->oldSize().width() )
{
// resize and reposition items
int totalHeight = 0,
newWidth = e->size().width();
QValueVector<Thumbnail *>::iterator thumbIt = thumbnails.begin();
......@@ -187,6 +200,10 @@ void ThumbnailList::viewportResizeEvent(QResizeEvent *e)
//BEGIN internal SLOTS
void ThumbnailList::slotRequestThumbnails( int /*newContentsX*/, int newContentsY )
{
// an update is already scheduled, so don't proceed
if ( m_delayTimer && m_delayTimer->isActive() )
return;
int vHeight = visibleHeight(),
vOffset = newContentsY == -1 ? contentsY() : newContentsY;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment