compile
[kdegraphics.git] / okular / ui / thumbnaillist.cpp
blob35fe76eed55c8e19676806b2f98d5f7aacd92b71
1 /***************************************************************************
2 * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 ***************************************************************************/
10 #include "thumbnaillist.h"
12 // qt/kde includes
13 #include <qevent.h>
14 #include <qtimer.h>
15 #include <qpainter.h>
16 #include <qscrollbar.h>
17 #include <qsizepolicy.h>
18 #include <klocale.h>
19 #include <kurl.h>
20 #include <kaction.h>
21 #include <kdialog.h>
22 #include <kiconloader.h>
23 #include <kactioncollection.h>
24 #include <kicon.h>
26 // local includes
27 #include "pagepainter.h"
28 #include "core/area.h"
29 #include "core/bookmarkmanager.h"
30 #include "core/document.h"
31 #include "core/generator.h"
32 #include "core/page.h"
33 #include "settings.h"
35 class ThumbnailWidget;
37 class ThumbnailListPrivate : public QWidget
39 public:
40 ThumbnailListPrivate( ThumbnailList *qq, Okular::Document *document );
41 ~ThumbnailListPrivate();
43 ThumbnailList *q;
44 Okular::Document *m_document;
45 ThumbnailWidget *m_selected;
46 QTimer *m_delayTimer;
47 QPixmap *m_bookmarkOverlay;
48 QVector<ThumbnailWidget *> m_thumbnails;
49 QList<ThumbnailWidget *> m_visibleThumbnails;
50 int m_vectorIndex;
51 QPoint mouseGrabPos;
52 // this is a (temporary) HACK to prevent jumping of the selected area
53 // when dragging the mouse between pages
54 ThumbnailWidget *mouseGrabItem;
56 // resize thumbnails to fit the width
57 void viewportResizeEvent( QResizeEvent * );
58 // called by ThumbnailWidgets to get the overlay bookmark pixmap
59 const QPixmap * getBookmarkOverlay() const;
60 // called by ThumbnailWidgets to send (forward) the mouse move signals
61 void forwardTrack( const Okular::Page *, const QPoint &, const QSize & );
63 ThumbnailWidget* itemFor( const QPoint & p ) const;
64 void delayedRequestVisiblePixmaps( int delayMs = 0 );
66 // SLOTS:
67 // make requests for generating pixmaps for visible thumbnails
68 void slotRequestVisiblePixmaps( int newContentsY = -1 );
69 // delay timeout: resize overlays and requests pixmaps
70 void slotDelayTimeout();
72 protected:
73 void mousePressEvent( QMouseEvent * e );
74 void mouseReleaseEvent( QMouseEvent * e );
75 void mouseMoveEvent( QMouseEvent * e );
76 void wheelEvent( QWheelEvent * e );
77 void contextMenuEvent( QContextMenuEvent * e );
78 void paintEvent( QPaintEvent * e );
82 // ThumbnailWidget represents a single thumbnail in the ThumbnailList
83 class ThumbnailWidget
85 public:
86 ThumbnailWidget( ThumbnailListPrivate * parent, const Okular::Page * page );
88 // set internal parameters to fit the page in the given width
89 void resizeFitWidth( int width );
90 // set thumbnail's selected state
91 void setSelected( bool selected );
92 // set the visible rect of the current page
93 void setVisibleRect( const Okular::NormalizedRect & rect );
95 // query methods
96 int heightHint() const { return m_pixmapHeight + m_labelHeight + m_margin; }
97 int pixmapWidth() const { return m_pixmapWidth; }
98 int pixmapHeight() const { return m_pixmapHeight; }
99 int pageNumber() const { return m_page->number(); }
100 const Okular::Page * page() const { return m_page; }
101 QRect visibleRect() const { return m_visibleRect.geometry( m_pixmapWidth, m_pixmapHeight ); }
103 void paint( QPainter &p, const QRect &clipRect );
105 static int margin() { return m_margin; }
107 // simulating QWidget
108 QRect rect() const { return m_rect; }
109 int height() const { return m_rect.height(); }
110 int width() const { return m_rect.width(); }
111 QPoint pos() const { return m_rect.topLeft(); }
112 void move( int x, int y ) { m_rect.setTopLeft( QPoint( x, y ) ); }
113 void update() { m_parent->update( m_rect ); }
114 void update( const QRect & rect ) { m_parent->update( rect.translated( m_rect.topLeft() ) ); }
116 private:
117 // the margin around the widget
118 static int const m_margin = 16;
120 ThumbnailListPrivate * m_parent;
121 const Okular::Page * m_page;
122 bool m_selected;
123 int m_pixmapWidth, m_pixmapHeight;
124 int m_labelHeight, m_labelNumber;
125 Okular::NormalizedRect m_visibleRect;
126 QRect m_rect;
130 ThumbnailListPrivate::ThumbnailListPrivate( ThumbnailList *qq, Okular::Document *document )
131 : QWidget(), q( qq ), m_document( document ), m_selected( 0 ),
132 m_delayTimer( 0 ), m_bookmarkOverlay( 0 )
134 setMouseTracking( true );
135 mouseGrabItem = 0;
138 ThumbnailListPrivate::~ThumbnailListPrivate()
142 ThumbnailWidget* ThumbnailListPrivate::itemFor( const QPoint & p ) const
144 QVector< ThumbnailWidget * >::const_iterator tIt = m_thumbnails.constBegin(), tEnd = m_thumbnails.constEnd();
145 for ( ; tIt != tEnd; ++tIt )
147 if ( (*tIt)->rect().contains( p ) )
148 return (*tIt);
150 return 0;
153 void ThumbnailListPrivate::paintEvent( QPaintEvent * e )
155 QPainter painter( this );
156 QVector<ThumbnailWidget *>::const_iterator tIt = m_thumbnails.constBegin(), tEnd = m_thumbnails.constEnd();
157 for ( ; tIt != tEnd; ++tIt )
159 QRect rect = e->rect().intersected( (*tIt)->rect() );
160 if ( !rect.isNull() )
162 rect.translate( -(*tIt)->pos() );
163 painter.save();
164 painter.translate( (*tIt)->pos() );
165 (*tIt)->paint( painter, rect );
166 painter.restore();
172 /** ThumbnailList implementation **/
174 ThumbnailList::ThumbnailList( QWidget *parent, Okular::Document *document )
175 : QScrollArea( parent ), d( new ThumbnailListPrivate( this, document ) )
177 setObjectName( "okular::Thumbnails" );
178 // set scrollbars
179 setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
180 setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
181 verticalScrollBar()->setEnabled( false );
183 setAttribute( Qt::WA_StaticContents );
185 setAcceptDrops( true );
187 QPalette pal = palette();
188 // set contents background to the 'base' color
189 QPalette viewportPal = viewport()->palette();
190 viewportPal.setColor( viewport()->backgroundRole(), pal.color( QPalette::Base ) );
191 viewport()->setPalette( viewportPal );
193 setWidget( d );
194 // widget setup: can be focused by tab and mouse click (not wheel)
195 widget()->setFocusPolicy( Qt::StrongFocus );
196 widget()->show();
197 QPalette widgetPal = widget()->palette();
198 widgetPal.setColor( widget()->backgroundRole(), pal.color( QPalette::Base ) );
199 widget()->setPalette( widgetPal );
201 connect( verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRequestVisiblePixmaps(int)) );
204 ThumbnailList::~ThumbnailList()
206 d->m_document->removeObserver( this );
207 delete d->m_bookmarkOverlay;
210 //BEGIN DocumentObserver inherited methods
211 void ThumbnailList::notifySetup( const QVector< Okular::Page * > & pages, int setupFlags )
213 // if there was a widget selected, save its pagenumber to restore
214 // its selection (if available in the new set of pages)
215 int prevPage = -1;
216 if ( !( setupFlags & Okular::DocumentObserver::DocumentChanged ) && d->m_selected )
218 prevPage = d->m_selected->page()->number();
219 } else
220 prevPage = d->m_document->viewport().pageNumber;
222 // delete all the Thumbnails
223 QVector<ThumbnailWidget *>::const_iterator tIt = d->m_thumbnails.constBegin(), tEnd = d->m_thumbnails.constEnd();
224 for ( ; tIt != tEnd; ++tIt )
225 delete *tIt;
226 d->m_thumbnails.clear();
227 d->m_visibleThumbnails.clear();
228 d->m_selected = 0;
229 d->mouseGrabItem = 0;
231 if ( pages.count() < 1 )
233 widget()->resize( 0, 0 );
234 return;
237 // show pages containing hilighted text or bookmarked ones
238 //RESTORE THIS int flags = Okular::Settings::filterBookmarks() ? Okular::Page::Bookmark : Okular::Page::Highlight;
240 // if no page matches filter rule, then display all pages
241 QVector< Okular::Page * >::const_iterator pIt = pages.constBegin(), pEnd = pages.constEnd();
242 bool skipCheck = true;
243 for ( ; pIt != pEnd ; ++pIt )
244 //if ( (*pIt)->attributes() & flags )
245 if ( (*pIt)->hasHighlights( SW_SEARCH_ID ) )
246 skipCheck = false;
248 // generate Thumbnails for the given set of pages
249 int width = viewport()->width();
250 int height = 0;
251 int centerHeight = 0;
252 for ( pIt = pages.constBegin(); pIt != pEnd ; ++pIt )
253 //if ( skipCheck || (*pIt)->attributes() & flags )
254 if ( skipCheck || (*pIt)->hasHighlights( SW_SEARCH_ID ) )
256 ThumbnailWidget * t = new ThumbnailWidget( d, *pIt );
257 t->move(0, height);
258 // add to the internal queue
259 d->m_thumbnails.push_back( t );
260 // update total height (asking widget its own height)
261 t->resizeFitWidth( width );
262 // restoring the previous selected page, if any
263 if ( (*pIt)->number() < prevPage )
265 centerHeight = height + t->height() + KDialog::spacingHint()/2;
267 if ( (*pIt)->number() == prevPage )
269 d->m_selected = t;
270 d->m_selected->setSelected( true );
271 centerHeight = height + t->height() / 2;
273 height += t->height() + KDialog::spacingHint();
276 // update scrollview's contents size (sets scrollbars limits)
277 height -= KDialog::spacingHint();
278 widget()->resize( width, height );
280 // enable scrollbar when there's something to scroll
281 verticalScrollBar()->setEnabled( viewport()->height() < height );
282 verticalScrollBar()->setValue(centerHeight - viewport()->height() / 2);
284 // request for thumbnail generation
285 d->delayedRequestVisiblePixmaps( 200 );
288 void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ )
290 // skip notifies for the current page (already selected)
291 int newPage = d->m_document->viewport().pageNumber;
292 if ( d->m_selected && d->m_selected->pageNumber() == newPage )
293 return;
295 // deselect previous thumbnail
296 if ( d->m_selected )
297 d->m_selected->setSelected( false );
298 d->m_selected = 0;
300 // select the page with viewport and ensure it's centered in the view
301 d->m_vectorIndex = 0;
302 QVector<ThumbnailWidget *>::const_iterator tIt = d->m_thumbnails.constBegin(), tEnd = d->m_thumbnails.constEnd();
303 for ( ; tIt != tEnd; ++tIt )
305 if ( (*tIt)->pageNumber() == newPage )
307 d->m_selected = *tIt;
308 d->m_selected->setSelected( true );
309 if ( Okular::Settings::syncThumbnailsViewport() )
311 int yOffset = qMax( viewport()->height() / 4, d->m_selected->height() / 2 );
312 ensureVisible( 0, d->m_selected->pos().y() + d->m_selected->height()/2, 0, yOffset );
314 break;
316 d->m_vectorIndex++;
320 void ThumbnailList::notifyPageChanged( int pageNumber, int changedFlags )
322 static int interestingFlags = DocumentObserver::Pixmap | DocumentObserver::Bookmark | DocumentObserver::Highlights | DocumentObserver::Annotations;
323 // only handle change notifications we are interested in
324 if ( !( changedFlags & interestingFlags ) )
325 return;
327 // iterate over visible items: if page(pageNumber) is one of them, repaint it
328 QList<ThumbnailWidget *>::const_iterator vIt = d->m_visibleThumbnails.constBegin(), vEnd = d->m_visibleThumbnails.constEnd();
329 for ( ; vIt != vEnd; ++vIt )
330 if ( (*vIt)->pageNumber() == pageNumber )
332 (*vIt)->update();
333 break;
337 void ThumbnailList::notifyContentsCleared( int changedFlags )
339 // if pixmaps were cleared, re-ask them
340 if ( changedFlags & DocumentObserver::Pixmap )
341 d->slotRequestVisiblePixmaps();
344 void ThumbnailList::notifyVisibleRectsChanged()
346 bool found = false;
347 const QVector<Okular::VisiblePageRect *> & visibleRects = d->m_document->visiblePageRects();
348 QVector<ThumbnailWidget *>::const_iterator tIt = d->m_thumbnails.constBegin(), tEnd = d->m_thumbnails.constEnd();
349 QVector<Okular::VisiblePageRect *>::const_iterator vEnd = visibleRects.end();
350 for ( ; tIt != tEnd; ++tIt )
352 found = false;
353 QVector<Okular::VisiblePageRect *>::const_iterator vIt = visibleRects.begin();
354 for ( ; ( vIt != vEnd ) && !found; ++vIt )
356 if ( (*tIt)->pageNumber() == (*vIt)->pageNumber )
358 (*tIt)->setVisibleRect( (*vIt)->rect );
359 found = true;
362 if ( !found )
364 (*tIt)->setVisibleRect( Okular::NormalizedRect() );
369 bool ThumbnailList::canUnloadPixmap( int pageNumber ) const
371 // if the thubnail 'pageNumber' is one of the visible ones, forbid unloading
372 QList<ThumbnailWidget *>::const_iterator vIt = d->m_visibleThumbnails.constBegin(), vEnd = d->m_visibleThumbnails.constEnd();
373 for ( ; vIt != vEnd; ++vIt )
374 if ( (*vIt)->pageNumber() == pageNumber )
375 return false;
376 // if hidden permit unloading
377 return true;
379 //END DocumentObserver inherited methods
382 void ThumbnailList::updateWidgets()
384 // find all widgets that intersects the viewport and update them
385 QRect viewportRect = viewport()->rect().translated( viewport()->pos() );
386 QList<ThumbnailWidget *>::const_iterator vIt = d->m_visibleThumbnails.constBegin(), vEnd = d->m_visibleThumbnails.constEnd();
387 for ( ; vIt != vEnd; ++vIt )
389 ThumbnailWidget * t = *vIt;
390 QRect thumbRect = t->rect().translated( widget()->mapToParent( t->pos() ) );
391 // update only the exposed area of the widget (saves pixels..)
392 QRect relativeRect = thumbRect.intersect( viewport()->rect() );
393 if ( !relativeRect.isValid() )
394 continue;
395 t->update( relativeRect );
399 void ThumbnailListPrivate::forwardTrack( const Okular::Page * p, const QPoint &point, const QSize &s )
401 Okular::DocumentViewport vp=m_document->viewport();
403 QVector< Okular::VisiblePageRect * > vVpr = m_document->visiblePageRects();
405 QVector< Okular::VisiblePageRect * >::const_iterator vIt = vVpr.constBegin();
406 QVector< Okular::VisiblePageRect * >::const_iterator vEnd = vVpr.constEnd();
407 for ( ; vIt != vEnd; ++vIt )
409 Okular::VisiblePageRect *vpr = ( *vIt );
410 if( vpr->pageNumber == p->number() )
412 double w = vpr->rect.right - vpr->rect.left,
413 h = vpr->rect.bottom - vpr->rect.top,
414 deltaX = (double)point.x() / s.width(),
415 deltaY = (double)point.y() / s.height();
417 vp.rePos.normalizedX -= deltaX;
418 vp.rePos.normalizedY -= deltaY;
420 if( !vp.rePos.enabled )
422 vp.rePos.enabled = true;
423 vp.rePos.normalizedY += h/2;
425 m_document->setViewport( vp );
426 break;
431 const QPixmap * ThumbnailListPrivate::getBookmarkOverlay() const
433 return m_bookmarkOverlay;
436 void ThumbnailList::slotFilterBookmarks( bool filterOn )
438 // save state
439 Okular::Settings::setFilterBookmarks( filterOn );
440 Okular::Settings::self()->writeConfig();
441 // ask for the 'notifySetup' with a little trick (on reinsertion the
442 // document sends the list again)
443 d->m_document->removeObserver( this );
444 d->m_document->addObserver( this );
448 //BEGIN widget events
449 void ThumbnailList::keyPressEvent( QKeyEvent * keyEvent )
451 if ( d->m_thumbnails.count() < 1 )
452 return keyEvent->ignore();
454 int nextPage = -1;
455 if ( keyEvent->key() == Qt::Key_Up )
457 if ( !d->m_selected )
458 nextPage = 0;
459 else if ( d->m_vectorIndex > 0 )
460 nextPage = d->m_thumbnails[ d->m_vectorIndex - 1 ]->pageNumber();
462 else if ( keyEvent->key() == Qt::Key_Down )
464 if ( !d->m_selected )
465 nextPage = 0;
466 else if ( d->m_vectorIndex < (int)d->m_thumbnails.count() - 1 )
467 nextPage = d->m_thumbnails[ d->m_vectorIndex + 1 ]->pageNumber();
469 else if ( keyEvent->key() == Qt::Key_PageUp )
470 verticalScrollBar()->triggerAction( QScrollBar::SliderPageStepSub );
471 else if ( keyEvent->key() == Qt::Key_PageDown )
472 verticalScrollBar()->triggerAction( QScrollBar::SliderPageStepAdd );
473 else if ( keyEvent->key() == Qt::Key_Home )
474 nextPage = d->m_thumbnails[ 0 ]->pageNumber();
475 else if ( keyEvent->key() == Qt::Key_End )
476 nextPage = d->m_thumbnails[ d->m_thumbnails.count() - 1 ]->pageNumber();
478 if ( nextPage == -1 )
479 return keyEvent->ignore();
481 keyEvent->accept();
482 if ( d->m_selected )
483 d->m_selected->setSelected( false );
484 d->m_selected = 0;
485 d->m_document->setViewportPage( nextPage );
488 bool ThumbnailList::viewportEvent( QEvent * e )
490 switch ( e->type() )
492 case QEvent::Resize:
494 d->viewportResizeEvent( (QResizeEvent*)e );
495 break;
497 default:
500 return QScrollArea::viewportEvent( e );
503 void ThumbnailListPrivate::viewportResizeEvent( QResizeEvent * e )
505 if ( m_thumbnails.count() < 1 || width() < 1 )
506 return;
508 // if width changed resize all the Thumbnails, reposition them to the
509 // right place and recalculate the contents area
510 if ( e->size().width() != e->oldSize().width() )
512 // runs the timer avoiding a thumbnail regeneration by 'contentsMoving'
513 delayedRequestVisiblePixmaps( 2000 );
515 // resize and reposition items
516 int newWidth = q->viewport()->width();
517 int newHeight = 0;
518 QVector<ThumbnailWidget *>::const_iterator tIt = m_thumbnails.constBegin(), tEnd = m_thumbnails.constEnd();
519 for ( ; tIt != tEnd; ++tIt )
521 ThumbnailWidget *t = *tIt;
522 t->move(0, newHeight);
523 t->resizeFitWidth( newWidth );
524 newHeight += t->height() + KDialog::spacingHint();
527 // update scrollview's contents size (sets scrollbars limits)
528 newHeight -= KDialog::spacingHint();
529 const int oldHeight = q->widget()->height();
530 const int oldYCenter = q->verticalScrollBar()->value() + q->viewport()->height() / 2;
531 q->widget()->resize( newWidth, newHeight );
533 // enable scrollbar when there's something to scroll
534 q->verticalScrollBar()->setEnabled( q->viewport()->height() < newHeight );
536 // ensure that what was visibile before remains visible now
537 q->ensureVisible( 0, int( (qreal)oldYCenter * q->widget()->height() / oldHeight ), 0, q->viewport()->height() / 2 );
539 else if ( e->size().height() <= e->oldSize().height() )
540 return;
542 // invalidate the bookmark overlay
543 if ( m_bookmarkOverlay )
545 delete m_bookmarkOverlay;
546 m_bookmarkOverlay = 0;
549 // update Thumbnails since width has changed or height has increased
550 delayedRequestVisiblePixmaps( 500 );
553 void ThumbnailList::dragEnterEvent( QDragEnterEvent * ev )
555 ev->accept();
558 void ThumbnailList::dropEvent( QDropEvent * ev )
560 if ( KUrl::List::canDecode( ev->mimeData() ) )
561 emit urlDropped( KUrl::List::fromMimeData( ev->mimeData() ).first() );
563 //END widget events
565 //BEGIN internal SLOTS
566 void ThumbnailListPrivate::slotRequestVisiblePixmaps( int /*newContentsY*/ )
568 // if an update is already scheduled or the widget is hidden, don't proceed
569 if ( ( m_delayTimer && m_delayTimer->isActive() ) || q->isHidden() )
570 return;
572 // scroll from the top to the last visible thumbnail
573 m_visibleThumbnails.clear();
574 QLinkedList< Okular::PixmapRequest * > requestedPixmaps;
575 QVector<ThumbnailWidget *>::const_iterator tIt = m_thumbnails.constBegin(), tEnd = m_thumbnails.constEnd();
576 QRect viewportRect = q->viewport()->rect().translated( q->horizontalScrollBar()->value(), q->verticalScrollBar()->value() );
577 for ( ; tIt != tEnd; ++tIt )
579 ThumbnailWidget * t = *tIt;
580 QRect thumbRect = t->rect();
581 if ( !thumbRect.intersects( viewportRect ) )
582 continue;
583 // add ThumbnailWidget to visible list
584 m_visibleThumbnails.push_back( t );
585 // if pixmap not present add it to requests
586 if ( !t->page()->hasPixmap( THUMBNAILS_ID, t->pixmapWidth(), t->pixmapHeight() ) )
588 Okular::PixmapRequest * p = new Okular::PixmapRequest(
589 THUMBNAILS_ID, t->pageNumber(), t->pixmapWidth(), t->pixmapHeight(), THUMBNAILS_PRIO, true );
590 requestedPixmaps.push_back( p );
594 // actually request pixmaps
595 if ( !requestedPixmaps.isEmpty() )
596 m_document->requestPixmaps( requestedPixmaps );
599 void ThumbnailListPrivate::slotDelayTimeout()
601 // resize the bookmark overlay
602 delete m_bookmarkOverlay;
603 int expectedWidth = q->viewport()->width() / 4;
604 if ( expectedWidth > 10 )
605 m_bookmarkOverlay = new QPixmap( DesktopIcon( "bookmarks", expectedWidth ) );
606 else
607 m_bookmarkOverlay = 0;
609 // request pixmaps
610 slotRequestVisiblePixmaps();
612 //END internal SLOTS
614 void ThumbnailListPrivate::delayedRequestVisiblePixmaps( int delayMs )
616 if ( !m_delayTimer )
618 m_delayTimer = new QTimer( q );
619 m_delayTimer->setSingleShot( true );
620 connect( m_delayTimer, SIGNAL( timeout() ), q, SLOT( slotDelayTimeout() ) );
622 m_delayTimer->start( delayMs );
626 /** ThumbnailWidget implementation **/
628 ThumbnailWidget::ThumbnailWidget( ThumbnailListPrivate * parent, const Okular::Page * kp )
629 : m_parent( parent ), m_page( kp ),
630 m_selected( false ), m_pixmapWidth( 10 ), m_pixmapHeight( 10 )
632 m_labelNumber = m_page->number() + 1;
633 m_labelHeight = QFontMetrics( m_parent->font() ).height();
637 void ThumbnailWidget::resizeFitWidth( int width )
639 m_pixmapWidth = width - m_margin;
640 m_pixmapHeight = qRound( m_page->ratio() * (double)m_pixmapWidth );
641 m_rect.setSize( QSize( width, heightHint() ) );
644 void ThumbnailWidget::setSelected( bool selected )
646 // update selected state
647 if ( m_selected != selected )
649 m_selected = selected;
650 update();
654 void ThumbnailWidget::setVisibleRect( const Okular::NormalizedRect & rect )
656 if ( rect == m_visibleRect )
657 return;
659 m_visibleRect = rect;
660 update();
663 void ThumbnailListPrivate::mousePressEvent( QMouseEvent * e )
665 ThumbnailWidget* item = itemFor( e->pos() );
666 if ( !item ) // mouse on the spacing between items
667 return e->ignore();
669 QRect r = item->visibleRect();
670 int margin = ThumbnailWidget::margin();
671 QPoint p = e->pos() - item->pos();
673 if ( e->button() != Qt::RightButton && r.contains( p - QPoint( margin / 2, margin / 2 ) ) )
675 mouseGrabPos = e->pos();
676 mouseGrabItem = item;
678 else
680 mouseGrabPos.setX( 0 );
681 mouseGrabPos.setY( 0 );
682 mouseGrabItem = 0;
686 void ThumbnailListPrivate::mouseReleaseEvent( QMouseEvent * e )
688 ThumbnailWidget* item = itemFor( e->pos() );
689 mouseGrabItem = item;
690 if ( !item ) // mouse on the spacing between items
691 return e->ignore();
693 QRect r = item->visibleRect();
694 int margin = ThumbnailWidget::margin();
695 QPoint p = e->pos() - item->pos();
697 if ( r.contains( p - QPoint( margin / 2, margin / 2 ) ) )
699 setCursor( Qt::OpenHandCursor );
701 else
703 setCursor( Qt::ArrowCursor );
704 if ( mouseGrabPos.isNull() )
706 if ( m_document->viewport().pageNumber != item->pageNumber() )
707 m_document->setViewportPage( item->pageNumber() );
710 mouseGrabPos.setX( 0 );
711 mouseGrabPos.setY( 0 );
714 void ThumbnailListPrivate::mouseMoveEvent( QMouseEvent * e )
716 ThumbnailWidget* item = itemFor( e->pos() );
717 if ( e->buttons() == Qt::NoButton )
718 return e->ignore();
720 ThumbnailWidget* theItem = item ? item : mouseGrabItem;
721 // no item under the mouse or previously selected
722 if ( !theItem )
723 return e->ignore();
724 QRect r = theItem->rect();
725 int margin = ThumbnailWidget::margin();
726 QPoint p = e->pos() - theItem->pos();
728 if ( true /*r.contains( p - QPoint( margin / 2, margin / 2 ) )*/ )
730 if ( !mouseGrabPos.isNull() )
732 setCursor( Qt::ClosedHandCursor );
733 QPoint mousePos = e->pos();
734 QPoint delta = mouseGrabPos - mousePos;
735 mouseGrabPos = e->pos();
736 if ( item )
737 mouseGrabItem = item;
738 // don't handle the mouse move, forward it to the thumbnail list
739 forwardTrack( mouseGrabItem->page(), delta, r.size() );
741 else
743 mouseGrabPos = QPoint();
744 mouseGrabItem = 0;
745 setCursor( Qt::OpenHandCursor );
748 else
750 setCursor( Qt::ArrowCursor );
754 void ThumbnailListPrivate::wheelEvent( QWheelEvent * e )
756 ThumbnailWidget* item = itemFor( e->pos() );
757 if ( !item ) // wheeling on the spacing between items
758 return e->ignore();
760 QRect r = item->visibleRect();
761 int margin = ThumbnailWidget::margin();
763 if ( r.contains( e->pos() - QPoint( margin / 2, margin / 2 ) ) && e->orientation() == Qt::Vertical && e->modifiers() == Qt::ControlModifier )
765 m_document->setZoom( e->delta() );
767 else
769 e->ignore();
773 void ThumbnailListPrivate::contextMenuEvent( QContextMenuEvent * e )
775 ThumbnailWidget* item = itemFor( e->pos() );
776 if ( item )
778 emit q->rightClick( item->page(), e->globalPos() );
782 void ThumbnailWidget::paint( QPainter &p, const QRect &_clipRect )
784 int width = m_pixmapWidth + m_margin;
785 QRect clipRect = _clipRect;
786 QPalette pal = m_parent->palette();
788 // draw the bottom label + highlight mark
789 QColor fillColor = m_selected ? pal.color( QPalette::Active, QPalette::Highlight ) : pal.color( QPalette::Active, QPalette::Base );
790 p.fillRect( clipRect, fillColor );
791 p.setPen( m_selected ? pal.color( QPalette::Active, QPalette::HighlightedText ) : pal.color( QPalette::Active, QPalette::Text ) );
792 p.drawText( 0, m_pixmapHeight + m_margin, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) );
794 // draw page outline and pixmap
795 if ( clipRect.top() < m_pixmapHeight + m_margin )
797 // if page is bookmarked draw a colored border
798 bool isBookmarked = m_parent->m_document->bookmarkManager()->isBookmarked( pageNumber() );
799 // draw the inner rect
800 p.setPen( isBookmarked ? QColor( 0xFF8000 ) : Qt::black );
801 p.drawRect( m_margin/2 - 1, m_margin/2 - 1, m_pixmapWidth + 1, m_pixmapHeight + 1 );
802 // draw the clear rect
803 p.setPen( isBookmarked ? QColor( 0x804000 ) : pal.color( QPalette::Active, QPalette::Base ) );
804 // draw the bottom and right shadow edges
805 if ( !isBookmarked )
807 int left, right, bottom, top;
808 left = m_margin/2 + 1;
809 right = m_margin/2 + m_pixmapWidth + 1;
810 bottom = m_pixmapHeight + m_margin/2 + 1;
811 top = m_margin/2 + 1;
812 p.setPen( Qt::gray );
813 p.drawLine( left, bottom, right, bottom );
814 p.drawLine( right, top, right, bottom );
817 // draw the page using the shared PagePainter class
818 p.translate( m_margin/2, m_margin/2 );
819 clipRect.translate( -m_margin/2, -m_margin/2 );
820 clipRect = clipRect.intersect( QRect( 0, 0, m_pixmapWidth, m_pixmapHeight ) );
821 if ( clipRect.isValid() )
823 int flags = PagePainter::Accessibility | PagePainter::Highlights |
824 PagePainter::Annotations;
825 PagePainter::paintPageOnPainter( &p, m_page, THUMBNAILS_ID, flags,
826 m_pixmapWidth, m_pixmapHeight, clipRect );
829 if ( !m_visibleRect.isNull() )
831 p.save();
832 p.setPen( QColor( 255, 255, 0, 200 ) );
833 p.setBrush( QColor( 0, 0, 0, 100 ) );
834 p.drawRect( m_visibleRect.geometry( m_pixmapWidth, m_pixmapHeight ).adjusted( 0, 0, -1, -1 ) );
835 p.restore();
838 // draw the bookmark overlay on the top-right corner
839 const QPixmap * bookmarkPixmap = m_parent->getBookmarkOverlay();
840 if ( isBookmarked && bookmarkPixmap )
842 int pixW = bookmarkPixmap->width(),
843 pixH = bookmarkPixmap->height();
844 clipRect = clipRect.intersect( QRect( m_pixmapWidth - pixW, 0, pixW, pixH ) );
845 if ( clipRect.isValid() )
846 p.drawPixmap( m_pixmapWidth - pixW, -pixH/8, *bookmarkPixmap );
852 /** ThumbnailsController implementation **/
854 #define FILTERB_ID 1
856 ThumbnailController::ThumbnailController( QWidget * parent, ThumbnailList * list )
857 : QToolBar( parent )
859 setObjectName( "ThumbsControlBar" );
860 // change toolbar appearance
861 setIconSize( QSize( 16, 16 ) );
862 setMovable( false );
863 QSizePolicy sp = sizePolicy();
864 sp.setVerticalPolicy( QSizePolicy::Minimum );
865 setSizePolicy( sp );
867 // insert a togglebutton [show only bookmarked pages]
868 //insertSeparator();
869 QAction * showBoomarkOnlyAction = addAction(
870 KIcon( "bookmarks" ), i18n( "Show bookmarked pages only" ) );
871 showBoomarkOnlyAction->setCheckable( true );
872 connect( showBoomarkOnlyAction, SIGNAL( toggled( bool ) ), list, SLOT( slotFilterBookmarks( bool ) ) );
873 showBoomarkOnlyAction->setChecked( Okular::Settings::filterBookmarks() );
874 //insertLineSeparator();
878 #include "thumbnaillist.moc"