/*************************************************************************** * Copyright (C) 2004-2006 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 "thumbnaillist.h" // qt/kde includes #include #include #include #include #include #include #include #include #include #include #include #include // local includes #include "pagepainter.h" #include "core/area.h" #include "core/bookmarkmanager.h" #include "core/document.h" #include "core/generator.h" #include "core/page.h" #include "settings.h" class ThumbnailWidget; class ThumbnailListPrivate : public QWidget { public: ThumbnailListPrivate( ThumbnailList *qq, Okular::Document *document ); ~ThumbnailListPrivate(); ThumbnailList *q; Okular::Document *m_document; ThumbnailWidget *m_selected; QTimer *m_delayTimer; QPixmap *m_bookmarkOverlay; QVector m_thumbnails; QList m_visibleThumbnails; int m_vectorIndex; QPoint mouseGrabPos; // this is a (temporary) HACK to prevent jumping of the selected area // when dragging the mouse between pages ThumbnailWidget *mouseGrabItem; // resize thumbnails to fit the width void viewportResizeEvent( QResizeEvent * ); // called by ThumbnailWidgets to get the overlay bookmark pixmap const QPixmap * getBookmarkOverlay() const; // called by ThumbnailWidgets to send (forward) the mouse move signals void forwardTrack( const Okular::Page *, const QPoint &, const QPoint & ); ThumbnailWidget* itemFor( const QPoint & p ) const; void delayedRequestVisiblePixmaps( int delayMs = 0 ); // SLOTS: // make requests for generating pixmaps for visible thumbnails void slotRequestVisiblePixmaps( int newContentsY = -1 ); // delay timeout: resize overlays and requests pixmaps void slotDelayTimeout(); protected: void mousePressEvent( QMouseEvent * e ); void mouseReleaseEvent( QMouseEvent * e ); void mouseMoveEvent( QMouseEvent * e ); void wheelEvent( QWheelEvent * e ); void contextMenuEvent( QContextMenuEvent * e ); void paintEvent( QPaintEvent * e ); }; // ThumbnailWidget represents a single thumbnail in the ThumbnailList class ThumbnailWidget { public: ThumbnailWidget( ThumbnailListPrivate * parent, const Okular::Page * page ); // set internal parameters to fit the page in the given width void resizeFitWidth( int width ); // set thumbnail's selected state void setSelected( bool selected ); // set the visible rect of the current page void setVisibleRect( const Okular::NormalizedRect & rect ); // query methods int heightHint() const { return m_pixmapHeight + m_labelHeight + m_margin; } int pixmapWidth() const { return m_pixmapWidth; } int pixmapHeight() const { return m_pixmapHeight; } int pageNumber() const { return m_page->number(); } const Okular::Page * page() const { return m_page; } QRect visibleRect() const { return m_visibleRect.geometry( m_pixmapWidth, m_pixmapHeight ); } void paint( QPainter &p, const QRect &clipRect ); static int margin() { return m_margin; } // simulating QWidget QRect rect() const { return m_rect; } int height() const { return m_rect.height(); } int width() const { return m_rect.width(); } QPoint pos() const { return m_rect.topLeft(); } void move( int x, int y ) { m_rect.setTopLeft( QPoint( x, y ) ); } void update() { m_parent->update( m_rect ); } void update( const QRect & rect ) { m_parent->update( rect.translated( m_rect.topLeft() ) ); } private: // the margin around the widget static int const m_margin = 16; ThumbnailListPrivate * m_parent; const Okular::Page * m_page; bool m_selected; int m_pixmapWidth, m_pixmapHeight; int m_labelHeight, m_labelNumber; Okular::NormalizedRect m_visibleRect; QRect m_rect; }; ThumbnailListPrivate::ThumbnailListPrivate( ThumbnailList *qq, Okular::Document *document ) : QWidget(), q( qq ), m_document( document ), m_selected( 0 ), m_delayTimer( 0 ), m_bookmarkOverlay( 0 ) { setMouseTracking( true ); mouseGrabItem = 0; } ThumbnailListPrivate::~ThumbnailListPrivate() { } ThumbnailWidget* ThumbnailListPrivate::itemFor( const QPoint & p ) const { QVector< ThumbnailWidget * >::const_iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { if ( (*tIt)->rect().contains( p ) ) return (*tIt); } return 0; } void ThumbnailListPrivate::paintEvent( QPaintEvent * e ) { QPainter painter( this ); QVector::const_iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { QRect rect = e->rect().intersected( (*tIt)->rect() ); if ( !rect.isNull() ) { rect.translate( -(*tIt)->pos() ); painter.save(); painter.translate( (*tIt)->pos() ); (*tIt)->paint( painter, rect ); painter.restore(); } } } /** ThumbnailList implementation **/ ThumbnailList::ThumbnailList( QWidget *parent, Okular::Document *document ) : QScrollArea( parent ), d( new ThumbnailListPrivate( this, document ) ) { setObjectName( "okular::Thumbnails" ); // set scrollbars setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); verticalScrollBar()->setEnabled( false ); setAttribute( Qt::WA_StaticContents ); setAcceptDrops( true ); QPalette pal = palette(); // set contents background to the 'base' color QPalette viewportPal = viewport()->palette(); viewportPal.setColor( viewport()->backgroundRole(), pal.color( QPalette::Base ) ); viewport()->setPalette( viewportPal ); setWidget( d ); // widget setup: can be focused by tab and mouse click (not wheel) widget()->setFocusPolicy( Qt::StrongFocus ); widget()->show(); QPalette widgetPal = widget()->palette(); widgetPal.setColor( widget()->backgroundRole(), pal.color( QPalette::Base ) ); widget()->setPalette( widgetPal ); setFrameStyle( StyledPanel | Raised ); connect( verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRequestVisiblePixmaps(int)) ); } ThumbnailList::~ThumbnailList() { d->m_document->removeObserver( this ); delete d->m_bookmarkOverlay; } //BEGIN DocumentObserver inherited methods void ThumbnailList::notifySetup( const QVector< Okular::Page * > & pages, int setupFlags ) { // if there was a widget selected, save its pagenumber to restore // its selection (if available in the new set of pages) int prevPage = -1; if ( !( setupFlags & Okular::DocumentObserver::DocumentChanged ) && d->m_selected ) { prevPage = d->m_selected->page()->number(); } // delete all the Thumbnails QVector::const_iterator tIt = d->m_thumbnails.begin(), tEnd = d->m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) delete *tIt; d->m_thumbnails.clear(); d->m_visibleThumbnails.clear(); d->m_selected = 0; if ( pages.count() < 1 ) { widget()->resize( 0, 0 ); return; } // show pages containing hilighted text or bookmarked ones //RESTORE THIS int flags = Okular::Settings::filterBookmarks() ? Okular::Page::Bookmark : Okular::Page::Highlight; // if no page matches filter rule, then display all pages QVector< Okular::Page * >::const_iterator pIt = pages.begin(), pEnd = pages.end(); bool skipCheck = true; for ( ; pIt != pEnd ; ++pIt ) //if ( (*pIt)->attributes() & flags ) if ( (*pIt)->hasHighlights( SW_SEARCH_ID ) ) skipCheck = false; // generate Thumbnails for the given set of pages int width = viewport()->width(); int height = 0; for ( pIt = pages.begin(); pIt != pEnd ; ++pIt ) //if ( skipCheck || (*pIt)->attributes() & flags ) if ( skipCheck || (*pIt)->hasHighlights( SW_SEARCH_ID ) ) { ThumbnailWidget * t = new ThumbnailWidget( d, *pIt ); t->move(0, height); // add to the internal queue d->m_thumbnails.push_back( t ); // update total height (asking widget its own height) t->resizeFitWidth( width ); // restoring the previous selected page, if any if ( (*pIt)->number() == prevPage ) { d->m_selected = t; d->m_selected->setSelected( true ); } height += t->height() + KDialog::spacingHint(); } // update scrollview's contents size (sets scrollbars limits) height -= KDialog::spacingHint(); widget()->resize( width, height ); // enable scrollbar when there's something to scroll verticalScrollBar()->setEnabled( viewport()->height() < height ); // request for thumbnail generation d->delayedRequestVisiblePixmaps( 200 ); } void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ ) { // skip notifies for the current page (already selected) int newPage = d->m_document->viewport().pageNumber; if ( d->m_selected && d->m_selected->pageNumber() == newPage ) return; // deselect previous thumbnail if ( d->m_selected ) d->m_selected->setSelected( false ); d->m_selected = 0; // select the page with viewport and ensure it's centered in the view d->m_vectorIndex = 0; QVector::const_iterator tIt = d->m_thumbnails.begin(), tEnd = d->m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { if ( (*tIt)->pageNumber() == newPage ) { d->m_selected = *tIt; d->m_selected->setSelected( true ); if ( Okular::Settings::syncThumbnailsViewport() ) { int yOffset = qMax( viewport()->height() / 4, d->m_selected->height() / 2 ); ensureVisible( 0, d->m_selected->pos().y() + d->m_selected->height()/2, 0, yOffset ); } break; } d->m_vectorIndex++; } } void ThumbnailList::notifyPageChanged( int pageNumber, int changedFlags ) { static int interestingFlags = DocumentObserver::Pixmap | DocumentObserver::Bookmark | DocumentObserver::Highlights | DocumentObserver::Annotations; // only handle change notifications we are interested in if ( !( changedFlags & interestingFlags ) ) return; // iterate over visible items: if page(pageNumber) is one of them, repaint it QList::const_iterator vIt = d->m_visibleThumbnails.begin(), vEnd = d->m_visibleThumbnails.end(); for ( ; vIt != vEnd; ++vIt ) if ( (*vIt)->pageNumber() == pageNumber ) { (*vIt)->update(); break; } } void ThumbnailList::notifyContentsCleared( int changedFlags ) { // if pixmaps were cleared, re-ask them if ( changedFlags & DocumentObserver::Pixmap ) d->slotRequestVisiblePixmaps(); } void ThumbnailList::notifyVisibleRectsChanged() { bool found = false; const QVector & visibleRects = d->m_document->visiblePageRects(); QVector::const_iterator tIt = d->m_thumbnails.constBegin(), tEnd = d->m_thumbnails.constEnd(); QVector::const_iterator vEnd = visibleRects.end(); for ( ; tIt != tEnd; ++tIt ) { found = false; QVector::const_iterator vIt = visibleRects.begin(); for ( ; ( vIt != vEnd ) && !found; ++vIt ) { if ( (*tIt)->pageNumber() == (*vIt)->pageNumber ) { (*tIt)->setVisibleRect( (*vIt)->rect ); found = true; } } if ( !found ) { (*tIt)->setVisibleRect( Okular::NormalizedRect() ); } } } bool ThumbnailList::canUnloadPixmap( int pageNumber ) const { // if the thubnail 'pageNumber' is one of the visible ones, forbid unloading QList::const_iterator vIt = d->m_visibleThumbnails.begin(), vEnd = d->m_visibleThumbnails.end(); for ( ; vIt != vEnd; ++vIt ) if ( (*vIt)->pageNumber() == pageNumber ) return false; // if hidden permit unloading return true; } //END DocumentObserver inherited methods void ThumbnailList::updateWidgets() { // find all widgets that intersects the viewport and update them QRect viewportRect = viewport()->rect().translated( viewport()->pos() ); QList::const_iterator vIt = d->m_visibleThumbnails.begin(), vEnd = d->m_visibleThumbnails.end(); for ( ; vIt != vEnd; ++vIt ) { ThumbnailWidget * t = *vIt; QRect thumbRect = t->rect().translated( widget()->mapToParent( t->pos() ) ); // update only the exposed area of the widget (saves pixels..) QRect relativeRect = thumbRect.intersect( viewport()->rect() ); if ( !relativeRect.isValid() ) continue; t->update( relativeRect ); } } void ThumbnailListPrivate::forwardTrack( const Okular::Page * p, const QPoint &point, const QPoint &s ) { Okular::DocumentViewport vp=m_document->viewport(); QVector< Okular::VisiblePageRect * > vVpr = m_document->visiblePageRects(); QVector< Okular::VisiblePageRect * >::const_iterator vIt = vVpr.begin(); QVector< Okular::VisiblePageRect * >::const_iterator vEnd = vVpr.end(); for ( ; vIt != vEnd; ++vIt ) { Okular::VisiblePageRect *vpr = ( *vIt ); if( vpr->pageNumber == p->number() ) { double w = vpr->rect.right - vpr->rect.left, h = vpr->rect.bottom - vpr->rect.top, deltaX = point.x()*w/s.x(), deltaY = point.y()*h/s.y(); vp.rePos.normalizedX -= deltaX; vp.rePos.normalizedY -= deltaY; if( !vp.rePos.enabled ) { vp.rePos.enabled = true; vp.rePos.normalizedY += h/2; } m_document->setViewport( vp ); } } } const QPixmap * ThumbnailListPrivate::getBookmarkOverlay() const { return m_bookmarkOverlay; } void ThumbnailList::slotFilterBookmarks( bool filterOn ) { // save state Okular::Settings::setFilterBookmarks( filterOn ); Okular::Settings::self()->writeConfig(); // ask for the 'notifySetup' with a little trick (on reinsertion the // document sends the list again) d->m_document->removeObserver( this ); d->m_document->addObserver( this ); } //BEGIN widget events void ThumbnailList::keyPressEvent( QKeyEvent * keyEvent ) { if ( d->m_thumbnails.count() < 1 ) return keyEvent->ignore(); int nextPage = -1; if ( keyEvent->key() == Qt::Key_Up ) { if ( !d->m_selected ) nextPage = 0; else if ( d->m_vectorIndex > 0 ) nextPage = d->m_thumbnails[ d->m_vectorIndex - 1 ]->pageNumber(); } else if ( keyEvent->key() == Qt::Key_Down ) { if ( !d->m_selected ) nextPage = 0; else if ( d->m_vectorIndex < (int)d->m_thumbnails.count() - 1 ) nextPage = d->m_thumbnails[ d->m_vectorIndex + 1 ]->pageNumber(); } else if ( keyEvent->key() == Qt::Key_PageUp ) verticalScrollBar()->triggerAction( QScrollBar::SliderPageStepSub ); else if ( keyEvent->key() == Qt::Key_PageDown ) verticalScrollBar()->triggerAction( QScrollBar::SliderPageStepAdd ); else if ( keyEvent->key() == Qt::Key_Home ) nextPage = d->m_thumbnails[ 0 ]->pageNumber(); else if ( keyEvent->key() == Qt::Key_End ) nextPage = d->m_thumbnails[ d->m_thumbnails.count() - 1 ]->pageNumber(); if ( nextPage == -1 ) return keyEvent->ignore(); keyEvent->accept(); if ( d->m_selected ) d->m_selected->setSelected( false ); d->m_selected = 0; d->m_document->setViewportPage( nextPage ); } bool ThumbnailList::viewportEvent( QEvent * e ) { switch ( e->type() ) { case QEvent::Resize: { d->viewportResizeEvent( (QResizeEvent*)e ); break; } default: ; } return QScrollArea::viewportEvent( e ); } void ThumbnailListPrivate::viewportResizeEvent( QResizeEvent * e ) { if ( m_thumbnails.count() < 1 || width() < 1 ) return; // if width changed resize all the Thumbnails, reposition them to the // right place and recalculate the contents area if ( e->size().width() != e->oldSize().width() ) { // runs the timer avoiding a thumbnail regeneration by 'contentsMoving' delayedRequestVisiblePixmaps( 2000 ); // resize and reposition items int newWidth = q->viewport()->width(); int newHeight = 0; QVector::const_iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); for ( ; tIt != tEnd; ++tIt ) { ThumbnailWidget *t = *tIt; t->move(0, newHeight); t->resizeFitWidth( newWidth ); newHeight += t->height() + KDialog::spacingHint(); } // update scrollview's contents size (sets scrollbars limits) newHeight -= KDialog::spacingHint(); q->widget()->resize( newWidth, newHeight ); // enable scrollbar when there's something to scroll q->verticalScrollBar()->setEnabled( q->viewport()->height() < newHeight ); // ensure selected item remains visible if ( m_selected ) q->ensureVisible( 0, m_selected->pos().y() + m_selected->height() / 2, 0, q->viewport()->height() / 2 ); } else if ( e->size().height() <= e->oldSize().height() ) return; // invalidate the bookmark overlay if ( m_bookmarkOverlay ) { delete m_bookmarkOverlay; m_bookmarkOverlay = 0; } // update Thumbnails since width has changed or height has increased delayedRequestVisiblePixmaps( 500 ); } void ThumbnailList::dragEnterEvent( QDragEnterEvent * ev ) { ev->accept(); } void ThumbnailList::dropEvent( QDropEvent * ev ) { if ( KUrl::List::canDecode( ev->mimeData() ) ) emit urlDropped( KUrl::List::fromMimeData( ev->mimeData() ).first() ); } //END widget events //BEGIN internal SLOTS void ThumbnailListPrivate::slotRequestVisiblePixmaps( int /*newContentsY*/ ) { // if an update is already scheduled or the widget is hidden, don't proceed if ( ( m_delayTimer && m_delayTimer->isActive() ) || q->isHidden() ) return; // scroll from the top to the last visible thumbnail m_visibleThumbnails.clear(); QLinkedList< Okular::PixmapRequest * > requestedPixmaps; QVector::const_iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end(); QRect viewportRect = q->viewport()->rect().translated( q->horizontalScrollBar()->value(), q->verticalScrollBar()->value() ); for ( ; tIt != tEnd; ++tIt ) { ThumbnailWidget * t = *tIt; QRect thumbRect = t->rect(); if ( !thumbRect.intersects( viewportRect ) ) continue; // add ThumbnailWidget to visible list m_visibleThumbnails.push_back( t ); // if pixmap not present add it to requests if ( !t->page()->hasPixmap( THUMBNAILS_ID, t->pixmapWidth(), t->pixmapHeight() ) ) { Okular::PixmapRequest * p = new Okular::PixmapRequest( THUMBNAILS_ID, t->pageNumber(), t->pixmapWidth(), t->pixmapHeight(), THUMBNAILS_PRIO, true ); requestedPixmaps.push_back( p ); } } // actually request pixmaps if ( !requestedPixmaps.isEmpty() ) m_document->requestPixmaps( requestedPixmaps ); } void ThumbnailListPrivate::slotDelayTimeout() { // resize the bookmark overlay delete m_bookmarkOverlay; int expectedWidth = q->viewport()->width() / 4; if ( expectedWidth > 10 ) m_bookmarkOverlay = new QPixmap( DesktopIcon( "bookmarks", expectedWidth ) ); else m_bookmarkOverlay = 0; // request pixmaps slotRequestVisiblePixmaps(); } //END internal SLOTS void ThumbnailListPrivate::delayedRequestVisiblePixmaps( int delayMs ) { if ( !m_delayTimer ) { m_delayTimer = new QTimer( q ); m_delayTimer->setSingleShot( true ); connect( m_delayTimer, SIGNAL( timeout() ), q, SLOT( slotDelayTimeout() ) ); } m_delayTimer->start( delayMs ); } /** ThumbnailWidget implementation **/ ThumbnailWidget::ThumbnailWidget( ThumbnailListPrivate * parent, const Okular::Page * kp ) : m_parent( parent ), m_page( kp ), m_selected( false ), m_pixmapWidth( 10 ), m_pixmapHeight( 10 ) { m_labelNumber = m_page->number() + 1; m_labelHeight = QFontMetrics( m_parent->font() ).height(); } void ThumbnailWidget::resizeFitWidth( int width ) { m_pixmapWidth = width - m_margin; m_pixmapHeight = qRound( m_page->ratio() * (double)m_pixmapWidth ); m_rect.setSize( QSize( width, heightHint() ) ); } void ThumbnailWidget::setSelected( bool selected ) { // update selected state if ( m_selected != selected ) { m_selected = selected; update(); } } void ThumbnailWidget::setVisibleRect( const Okular::NormalizedRect & rect ) { if ( rect == m_visibleRect ) return; m_visibleRect = rect; update(); } void ThumbnailListPrivate::mousePressEvent( QMouseEvent * e ) { ThumbnailWidget* item = itemFor( e->pos() ); if ( !item ) // mouse on the spacing between items return e->ignore(); QRect r = item->visibleRect(); int margin = ThumbnailWidget::margin(); QPoint p = e->pos() - item->pos(); if ( e->button() != Qt::RightButton && r.contains( p - QPoint( margin / 2, margin / 2 ) ) ) { mouseGrabPos = e->pos(); mouseGrabItem = item; } else { mouseGrabPos.setX( 0 ); mouseGrabPos.setY( 0 ); mouseGrabItem = 0; } } void ThumbnailListPrivate::mouseReleaseEvent( QMouseEvent * e ) { ThumbnailWidget* item = itemFor( e->pos() ); if ( !item ) // mouse on the spacing between items return e->ignore(); QRect r = item->visibleRect(); int margin = ThumbnailWidget::margin(); QPoint p = e->pos() - item->pos(); if ( r.contains( p - QPoint( margin / 2, margin / 2 ) ) ) { setCursor( Qt::OpenHandCursor ); } else { setCursor( Qt::ArrowCursor ); if ( mouseGrabPos.isNull() ) { if ( m_document->viewport().pageNumber != item->pageNumber() ) m_document->setViewportPage( item->pageNumber() ); } } mouseGrabPos.setX( 0 ); mouseGrabPos.setY( 0 ); mouseGrabItem = item; } void ThumbnailListPrivate::mouseMoveEvent( QMouseEvent * e ) { ThumbnailWidget* item = itemFor( e->pos() ); if ( !item ) // mouse on the spacing between items return e->ignore(); QRect r = item->visibleRect(); int margin = ThumbnailWidget::margin(); QPoint p = e->pos() - item->pos(); if ( r.contains( p - QPoint( margin / 2, margin / 2 ) ) ) { if ( !mouseGrabPos.isNull() && mouseGrabItem == item ) { setCursor( Qt::ClosedHandCursor ); QPoint mousePos = e->pos(); QPoint delta = mouseGrabPos - mousePos; // don't handle the mouse move, forward it to the thumbnail list forwardTrack( item->page(), delta, QPoint( r.width(), r.height() ) ); mouseGrabPos = e->pos(); } else { mouseGrabPos = QPoint(); mouseGrabItem = 0; setCursor( Qt::OpenHandCursor ); } } else { setCursor( Qt::ArrowCursor ); } } void ThumbnailListPrivate::wheelEvent( QWheelEvent * e ) { ThumbnailWidget* item = itemFor( e->pos() ); if ( !item ) // wheeling on the spacing between items return e->ignore(); QRect r = item->visibleRect(); int margin = ThumbnailWidget::margin(); if ( r.contains( e->pos() - QPoint( margin / 2, margin / 2 ) ) && e->orientation() == Qt::Vertical && e->modifiers() == Qt::ControlModifier ) { m_document->setZoom( e->delta() ); } else { e->ignore(); } } void ThumbnailListPrivate::contextMenuEvent( QContextMenuEvent * e ) { ThumbnailWidget* item = itemFor( e->pos() ); if ( item ) { emit q->rightClick( item->page(), e->globalPos() ); } } void ThumbnailWidget::paint( QPainter &p, const QRect &_clipRect ) { int width = m_pixmapWidth + m_margin; QRect clipRect = _clipRect; QPalette pal = m_parent->palette(); // draw the bottom label + highlight mark QColor fillColor = m_selected ? pal.color( QPalette::Active, QPalette::Highlight ) : pal.color( QPalette::Active, QPalette::Base ); p.fillRect( clipRect, fillColor ); p.setPen( m_selected ? pal.color( QPalette::Active, QPalette::HighlightedText ) : pal.color( QPalette::Active, QPalette::Text ) ); p.drawText( 0, m_pixmapHeight + m_margin, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) ); // draw page outline and pixmap if ( clipRect.top() < m_pixmapHeight + m_margin ) { // if page is bookmarked draw a colored border bool isBookmarked = m_parent->m_document->bookmarkManager()->isBookmarked( pageNumber() ); // draw the inner rect p.setPen( isBookmarked ? QColor( 0xFF8000 ) : Qt::black ); p.drawRect( m_margin/2 - 1, m_margin/2 - 1, m_pixmapWidth + 1, m_pixmapHeight + 1 ); // draw the clear rect p.setPen( isBookmarked ? QColor( 0x804000 ) : pal.color( QPalette::Active, QPalette::Base ) ); // draw the bottom and right shadow edges if ( !isBookmarked ) { int left, right, bottom, top; left = m_margin/2 + 1; right = m_margin/2 + m_pixmapWidth + 1; bottom = m_pixmapHeight + m_margin/2 + 1; top = m_margin/2 + 1; p.setPen( Qt::gray ); p.drawLine( left, bottom, right, bottom ); p.drawLine( right, top, right, bottom ); } // draw the page using the shared PagePainter class p.translate( m_margin/2, m_margin/2 ); clipRect.translate( -m_margin/2, -m_margin/2 ); clipRect = clipRect.intersect( QRect( 0, 0, m_pixmapWidth, m_pixmapHeight ) ); if ( clipRect.isValid() ) { int flags = PagePainter::Accessibility | PagePainter::Highlights | PagePainter::Annotations; PagePainter::paintPageOnPainter( &p, m_page, THUMBNAILS_ID, flags, m_pixmapWidth, m_pixmapHeight, clipRect ); } if ( !m_visibleRect.isNull() ) { p.save(); p.setPen( QColor( 255, 255, 0, 200 ) ); p.setBrush( QColor( 0, 0, 0, 100 ) ); p.drawRect( m_visibleRect.geometry( m_pixmapWidth, m_pixmapHeight ).adjusted( 0, 0, -1, -1 ) ); p.restore(); } // draw the bookmark overlay on the top-right corner const QPixmap * bookmarkPixmap = m_parent->getBookmarkOverlay(); if ( isBookmarked && bookmarkPixmap ) { int pixW = bookmarkPixmap->width(), pixH = bookmarkPixmap->height(); clipRect = clipRect.intersect( QRect( m_pixmapWidth - pixW, 0, pixW, pixH ) ); if ( clipRect.isValid() ) p.drawPixmap( m_pixmapWidth - pixW, -pixH/8, *bookmarkPixmap ); } } } /** ThumbnailsController implementation **/ #define FILTERB_ID 1 ThumbnailController::ThumbnailController( QWidget * parent, ThumbnailList * list ) : QToolBar( parent ) { setObjectName( "ThumbsControlBar" ); // change toolbar appearance setIconSize( QSize( 16, 16 ) ); setMovable( false ); QSizePolicy sp = sizePolicy(); sp.setVerticalPolicy( QSizePolicy::Minimum ); setSizePolicy( sp ); // insert a togglebutton [show only bookmarked pages] //insertSeparator(); QAction * showBoomarkOnlyAction = addAction( KIcon( "bookmarks" ), i18n( "Show bookmarked pages only" ) ); showBoomarkOnlyAction->setCheckable( true ); connect( showBoomarkOnlyAction, SIGNAL( toggled( bool ) ), list, SLOT( slotFilterBookmarks( bool ) ) ); showBoomarkOnlyAction->setChecked( Okular::Settings::filterBookmarks() ); //insertLineSeparator(); } #include "thumbnaillist.moc"