compile
[kdegraphics.git] / okular / ui / thumbnaillist.cpp
blobbae9d83ebc64cd88aab0dc116c5fd19ba48e9962
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.begin(), tEnd = m_thumbnails.end();
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.begin(), tEnd = m_thumbnails.end();
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();
221 // delete all the Thumbnails
222 QVector<ThumbnailWidget *>::const_iterator tIt = d->m_thumbnails.begin(), tEnd = d->m_thumbnails.end();
223 for ( ; tIt != tEnd; ++tIt )
224 delete *tIt;
225 d->m_thumbnails.clear();
226 d->m_visibleThumbnails.clear();
227 d->m_selected = 0;
228 d->mouseGrabItem = 0;
230 if ( pages.count() < 1 )
232 widget()->resize( 0, 0 );
233 return;
236 // show pages containing hilighted text or bookmarked ones
237 //RESTORE THIS int flags = Okular::Settings::filterBookmarks() ? Okular::Page::Bookmark : Okular::Page::Highlight;
239 // if no page matches filter rule, then display all pages
240 QVector< Okular::Page * >::const_iterator pIt = pages.begin(), pEnd = pages.end();
241 bool skipCheck = true;
242 for ( ; pIt != pEnd ; ++pIt )
243 //if ( (*pIt)->attributes() & flags )
244 if ( (*pIt)->hasHighlights( SW_SEARCH_ID ) )
245 skipCheck = false;
247 // generate Thumbnails for the given set of pages
248 int width = viewport()->width();
249 int height = 0;
250 for ( pIt = pages.begin(); pIt != pEnd ; ++pIt )
251 //if ( skipCheck || (*pIt)->attributes() & flags )
252 if ( skipCheck || (*pIt)->hasHighlights( SW_SEARCH_ID ) )
254 ThumbnailWidget * t = new ThumbnailWidget( d, *pIt );
255 t->move(0, height);
256 // add to the internal queue
257 d->m_thumbnails.push_back( t );
258 // update total height (asking widget its own height)
259 t->resizeFitWidth( width );
260 // restoring the previous selected page, if any
261 if ( (*pIt)->number() == prevPage )
263 d->m_selected = t;
264 d->m_selected->setSelected( true );
266 height += t->height() + KDialog::spacingHint();
269 // update scrollview's contents size (sets scrollbars limits)
270 height -= KDialog::spacingHint();
271 widget()->resize( width, height );
273 // enable scrollbar when there's something to scroll
274 verticalScrollBar()->setEnabled( viewport()->height() < height );
276 // request for thumbnail generation
277 d->delayedRequestVisiblePixmaps( 200 );
280 void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ )
282 // skip notifies for the current page (already selected)
283 int newPage = d->m_document->viewport().pageNumber;
284 if ( d->m_selected && d->m_selected->pageNumber() == newPage )
285 return;
287 // deselect previous thumbnail
288 if ( d->m_selected )
289 d->m_selected->setSelected( false );
290 d->m_selected = 0;
292 // select the page with viewport and ensure it's centered in the view
293 d->m_vectorIndex = 0;
294 QVector<ThumbnailWidget *>::const_iterator tIt = d->m_thumbnails.begin(), tEnd = d->m_thumbnails.end();
295 for ( ; tIt != tEnd; ++tIt )
297 if ( (*tIt)->pageNumber() == newPage )
299 d->m_selected = *tIt;
300 d->m_selected->setSelected( true );
301 if ( Okular::Settings::syncThumbnailsViewport() )
303 int yOffset = qMax( viewport()->height() / 4, d->m_selected->height() / 2 );
304 ensureVisible( 0, d->m_selected->pos().y() + d->m_selected->height()/2, 0, yOffset );
306 break;
308 d->m_vectorIndex++;
312 void ThumbnailList::notifyPageChanged( int pageNumber, int changedFlags )
314 static int interestingFlags = DocumentObserver::Pixmap | DocumentObserver::Bookmark | DocumentObserver::Highlights | DocumentObserver::Annotations;
315 // only handle change notifications we are interested in
316 if ( !( changedFlags & interestingFlags ) )
317 return;
319 // iterate over visible items: if page(pageNumber) is one of them, repaint it
320 QList<ThumbnailWidget *>::const_iterator vIt = d->m_visibleThumbnails.begin(), vEnd = d->m_visibleThumbnails.end();
321 for ( ; vIt != vEnd; ++vIt )
322 if ( (*vIt)->pageNumber() == pageNumber )
324 (*vIt)->update();
325 break;
329 void ThumbnailList::notifyContentsCleared( int changedFlags )
331 // if pixmaps were cleared, re-ask them
332 if ( changedFlags & DocumentObserver::Pixmap )
333 d->slotRequestVisiblePixmaps();
336 void ThumbnailList::notifyVisibleRectsChanged()
338 bool found = false;
339 const QVector<Okular::VisiblePageRect *> & visibleRects = d->m_document->visiblePageRects();
340 QVector<ThumbnailWidget *>::const_iterator tIt = d->m_thumbnails.constBegin(), tEnd = d->m_thumbnails.constEnd();
341 QVector<Okular::VisiblePageRect *>::const_iterator vEnd = visibleRects.end();
342 for ( ; tIt != tEnd; ++tIt )
344 found = false;
345 QVector<Okular::VisiblePageRect *>::const_iterator vIt = visibleRects.begin();
346 for ( ; ( vIt != vEnd ) && !found; ++vIt )
348 if ( (*tIt)->pageNumber() == (*vIt)->pageNumber )
350 (*tIt)->setVisibleRect( (*vIt)->rect );
351 found = true;
354 if ( !found )
356 (*tIt)->setVisibleRect( Okular::NormalizedRect() );
361 bool ThumbnailList::canUnloadPixmap( int pageNumber ) const
363 // if the thubnail 'pageNumber' is one of the visible ones, forbid unloading
364 QList<ThumbnailWidget *>::const_iterator vIt = d->m_visibleThumbnails.begin(), vEnd = d->m_visibleThumbnails.end();
365 for ( ; vIt != vEnd; ++vIt )
366 if ( (*vIt)->pageNumber() == pageNumber )
367 return false;
368 // if hidden permit unloading
369 return true;
371 //END DocumentObserver inherited methods
374 void ThumbnailList::updateWidgets()
376 // find all widgets that intersects the viewport and update them
377 QRect viewportRect = viewport()->rect().translated( viewport()->pos() );
378 QList<ThumbnailWidget *>::const_iterator vIt = d->m_visibleThumbnails.begin(), vEnd = d->m_visibleThumbnails.end();
379 for ( ; vIt != vEnd; ++vIt )
381 ThumbnailWidget * t = *vIt;
382 QRect thumbRect = t->rect().translated( widget()->mapToParent( t->pos() ) );
383 // update only the exposed area of the widget (saves pixels..)
384 QRect relativeRect = thumbRect.intersect( viewport()->rect() );
385 if ( !relativeRect.isValid() )
386 continue;
387 t->update( relativeRect );
391 void ThumbnailListPrivate::forwardTrack( const Okular::Page * p, const QPoint &point, const QSize &s )
393 Okular::DocumentViewport vp=m_document->viewport();
395 QVector< Okular::VisiblePageRect * > vVpr = m_document->visiblePageRects();
397 QVector< Okular::VisiblePageRect * >::const_iterator vIt = vVpr.begin();
398 QVector< Okular::VisiblePageRect * >::const_iterator vEnd = vVpr.end();
399 for ( ; vIt != vEnd; ++vIt )
401 Okular::VisiblePageRect *vpr = ( *vIt );
402 if( vpr->pageNumber == p->number() )
404 double w = vpr->rect.right - vpr->rect.left,
405 h = vpr->rect.bottom - vpr->rect.top,
406 deltaX = (double)point.x() / s.width(),
407 deltaY = (double)point.y() / s.height();
409 vp.rePos.normalizedX -= deltaX;
410 vp.rePos.normalizedY -= deltaY;
412 if( !vp.rePos.enabled )
414 vp.rePos.enabled = true;
415 vp.rePos.normalizedY += h/2;
417 m_document->setViewport( vp );
418 break;
423 const QPixmap * ThumbnailListPrivate::getBookmarkOverlay() const
425 return m_bookmarkOverlay;
428 void ThumbnailList::slotFilterBookmarks( bool filterOn )
430 // save state
431 Okular::Settings::setFilterBookmarks( filterOn );
432 Okular::Settings::self()->writeConfig();
433 // ask for the 'notifySetup' with a little trick (on reinsertion the
434 // document sends the list again)
435 d->m_document->removeObserver( this );
436 d->m_document->addObserver( this );
440 //BEGIN widget events
441 void ThumbnailList::keyPressEvent( QKeyEvent * keyEvent )
443 if ( d->m_thumbnails.count() < 1 )
444 return keyEvent->ignore();
446 int nextPage = -1;
447 if ( keyEvent->key() == Qt::Key_Up )
449 if ( !d->m_selected )
450 nextPage = 0;
451 else if ( d->m_vectorIndex > 0 )
452 nextPage = d->m_thumbnails[ d->m_vectorIndex - 1 ]->pageNumber();
454 else if ( keyEvent->key() == Qt::Key_Down )
456 if ( !d->m_selected )
457 nextPage = 0;
458 else if ( d->m_vectorIndex < (int)d->m_thumbnails.count() - 1 )
459 nextPage = d->m_thumbnails[ d->m_vectorIndex + 1 ]->pageNumber();
461 else if ( keyEvent->key() == Qt::Key_PageUp )
462 verticalScrollBar()->triggerAction( QScrollBar::SliderPageStepSub );
463 else if ( keyEvent->key() == Qt::Key_PageDown )
464 verticalScrollBar()->triggerAction( QScrollBar::SliderPageStepAdd );
465 else if ( keyEvent->key() == Qt::Key_Home )
466 nextPage = d->m_thumbnails[ 0 ]->pageNumber();
467 else if ( keyEvent->key() == Qt::Key_End )
468 nextPage = d->m_thumbnails[ d->m_thumbnails.count() - 1 ]->pageNumber();
470 if ( nextPage == -1 )
471 return keyEvent->ignore();
473 keyEvent->accept();
474 if ( d->m_selected )
475 d->m_selected->setSelected( false );
476 d->m_selected = 0;
477 d->m_document->setViewportPage( nextPage );
480 bool ThumbnailList::viewportEvent( QEvent * e )
482 switch ( e->type() )
484 case QEvent::Resize:
486 d->viewportResizeEvent( (QResizeEvent*)e );
487 break;
489 default:
492 return QScrollArea::viewportEvent( e );
495 void ThumbnailListPrivate::viewportResizeEvent( QResizeEvent * e )
497 if ( m_thumbnails.count() < 1 || width() < 1 )
498 return;
500 // if width changed resize all the Thumbnails, reposition them to the
501 // right place and recalculate the contents area
502 if ( e->size().width() != e->oldSize().width() )
504 // runs the timer avoiding a thumbnail regeneration by 'contentsMoving'
505 delayedRequestVisiblePixmaps( 2000 );
507 // resize and reposition items
508 int newWidth = q->viewport()->width();
509 int newHeight = 0;
510 QVector<ThumbnailWidget *>::const_iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end();
511 for ( ; tIt != tEnd; ++tIt )
513 ThumbnailWidget *t = *tIt;
514 t->move(0, newHeight);
515 t->resizeFitWidth( newWidth );
516 newHeight += t->height() + KDialog::spacingHint();
519 // update scrollview's contents size (sets scrollbars limits)
520 newHeight -= KDialog::spacingHint();
521 q->widget()->resize( newWidth, newHeight );
523 // enable scrollbar when there's something to scroll
524 q->verticalScrollBar()->setEnabled( q->viewport()->height() < newHeight );
526 // ensure selected item remains visible
527 if ( m_selected )
528 q->ensureVisible( 0, m_selected->pos().y() + m_selected->height() / 2, 0, q->viewport()->height() / 2 );
530 else if ( e->size().height() <= e->oldSize().height() )
531 return;
533 // invalidate the bookmark overlay
534 if ( m_bookmarkOverlay )
536 delete m_bookmarkOverlay;
537 m_bookmarkOverlay = 0;
540 // update Thumbnails since width has changed or height has increased
541 delayedRequestVisiblePixmaps( 500 );
544 void ThumbnailList::dragEnterEvent( QDragEnterEvent * ev )
546 ev->accept();
549 void ThumbnailList::dropEvent( QDropEvent * ev )
551 if ( KUrl::List::canDecode( ev->mimeData() ) )
552 emit urlDropped( KUrl::List::fromMimeData( ev->mimeData() ).first() );
554 //END widget events
556 //BEGIN internal SLOTS
557 void ThumbnailListPrivate::slotRequestVisiblePixmaps( int /*newContentsY*/ )
559 // if an update is already scheduled or the widget is hidden, don't proceed
560 if ( ( m_delayTimer && m_delayTimer->isActive() ) || q->isHidden() )
561 return;
563 // scroll from the top to the last visible thumbnail
564 m_visibleThumbnails.clear();
565 QLinkedList< Okular::PixmapRequest * > requestedPixmaps;
566 QVector<ThumbnailWidget *>::const_iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end();
567 QRect viewportRect = q->viewport()->rect().translated( q->horizontalScrollBar()->value(), q->verticalScrollBar()->value() );
568 for ( ; tIt != tEnd; ++tIt )
570 ThumbnailWidget * t = *tIt;
571 QRect thumbRect = t->rect();
572 if ( !thumbRect.intersects( viewportRect ) )
573 continue;
574 // add ThumbnailWidget to visible list
575 m_visibleThumbnails.push_back( t );
576 // if pixmap not present add it to requests
577 if ( !t->page()->hasPixmap( THUMBNAILS_ID, t->pixmapWidth(), t->pixmapHeight() ) )
579 Okular::PixmapRequest * p = new Okular::PixmapRequest(
580 THUMBNAILS_ID, t->pageNumber(), t->pixmapWidth(), t->pixmapHeight(), THUMBNAILS_PRIO, true );
581 requestedPixmaps.push_back( p );
585 // actually request pixmaps
586 if ( !requestedPixmaps.isEmpty() )
587 m_document->requestPixmaps( requestedPixmaps );
590 void ThumbnailListPrivate::slotDelayTimeout()
592 // resize the bookmark overlay
593 delete m_bookmarkOverlay;
594 int expectedWidth = q->viewport()->width() / 4;
595 if ( expectedWidth > 10 )
596 m_bookmarkOverlay = new QPixmap( DesktopIcon( "bookmarks", expectedWidth ) );
597 else
598 m_bookmarkOverlay = 0;
600 // request pixmaps
601 slotRequestVisiblePixmaps();
603 //END internal SLOTS
605 void ThumbnailListPrivate::delayedRequestVisiblePixmaps( int delayMs )
607 if ( !m_delayTimer )
609 m_delayTimer = new QTimer( q );
610 m_delayTimer->setSingleShot( true );
611 connect( m_delayTimer, SIGNAL( timeout() ), q, SLOT( slotDelayTimeout() ) );
613 m_delayTimer->start( delayMs );
617 /** ThumbnailWidget implementation **/
619 ThumbnailWidget::ThumbnailWidget( ThumbnailListPrivate * parent, const Okular::Page * kp )
620 : m_parent( parent ), m_page( kp ),
621 m_selected( false ), m_pixmapWidth( 10 ), m_pixmapHeight( 10 )
623 m_labelNumber = m_page->number() + 1;
624 m_labelHeight = QFontMetrics( m_parent->font() ).height();
628 void ThumbnailWidget::resizeFitWidth( int width )
630 m_pixmapWidth = width - m_margin;
631 m_pixmapHeight = qRound( m_page->ratio() * (double)m_pixmapWidth );
632 m_rect.setSize( QSize( width, heightHint() ) );
635 void ThumbnailWidget::setSelected( bool selected )
637 // update selected state
638 if ( m_selected != selected )
640 m_selected = selected;
641 update();
645 void ThumbnailWidget::setVisibleRect( const Okular::NormalizedRect & rect )
647 if ( rect == m_visibleRect )
648 return;
650 m_visibleRect = rect;
651 update();
654 void ThumbnailListPrivate::mousePressEvent( QMouseEvent * e )
656 ThumbnailWidget* item = itemFor( e->pos() );
657 if ( !item ) // mouse on the spacing between items
658 return e->ignore();
660 QRect r = item->visibleRect();
661 int margin = ThumbnailWidget::margin();
662 QPoint p = e->pos() - item->pos();
664 if ( e->button() != Qt::RightButton && r.contains( p - QPoint( margin / 2, margin / 2 ) ) )
666 mouseGrabPos = e->pos();
667 mouseGrabItem = item;
669 else
671 mouseGrabPos.setX( 0 );
672 mouseGrabPos.setY( 0 );
673 mouseGrabItem = 0;
677 void ThumbnailListPrivate::mouseReleaseEvent( QMouseEvent * e )
679 ThumbnailWidget* item = itemFor( e->pos() );
680 mouseGrabItem = item;
681 if ( !item ) // mouse on the spacing between items
682 return e->ignore();
684 QRect r = item->visibleRect();
685 int margin = ThumbnailWidget::margin();
686 QPoint p = e->pos() - item->pos();
688 if ( r.contains( p - QPoint( margin / 2, margin / 2 ) ) )
690 setCursor( Qt::OpenHandCursor );
692 else
694 setCursor( Qt::ArrowCursor );
695 if ( mouseGrabPos.isNull() )
697 if ( m_document->viewport().pageNumber != item->pageNumber() )
698 m_document->setViewportPage( item->pageNumber() );
701 mouseGrabPos.setX( 0 );
702 mouseGrabPos.setY( 0 );
705 void ThumbnailListPrivate::mouseMoveEvent( QMouseEvent * e )
707 ThumbnailWidget* item = itemFor( e->pos() );
708 if ( e->buttons() == Qt::NoButton )
709 return e->ignore();
711 ThumbnailWidget* theItem = item ? item : mouseGrabItem;
712 // no item under the mouse or previously selected
713 if ( !theItem )
714 return e->ignore();
715 QRect r = theItem->rect();
716 int margin = ThumbnailWidget::margin();
717 QPoint p = e->pos() - theItem->pos();
719 if ( true /*r.contains( p - QPoint( margin / 2, margin / 2 ) )*/ )
721 if ( !mouseGrabPos.isNull() )
723 setCursor( Qt::ClosedHandCursor );
724 QPoint mousePos = e->pos();
725 QPoint delta = mouseGrabPos - mousePos;
726 mouseGrabPos = e->pos();
727 if ( item )
728 mouseGrabItem = item;
729 // don't handle the mouse move, forward it to the thumbnail list
730 forwardTrack( mouseGrabItem->page(), delta, r.size() );
732 else
734 mouseGrabPos = QPoint();
735 mouseGrabItem = 0;
736 setCursor( Qt::OpenHandCursor );
739 else
741 setCursor( Qt::ArrowCursor );
745 void ThumbnailListPrivate::wheelEvent( QWheelEvent * e )
747 ThumbnailWidget* item = itemFor( e->pos() );
748 if ( !item ) // wheeling on the spacing between items
749 return e->ignore();
751 QRect r = item->visibleRect();
752 int margin = ThumbnailWidget::margin();
754 if ( r.contains( e->pos() - QPoint( margin / 2, margin / 2 ) ) && e->orientation() == Qt::Vertical && e->modifiers() == Qt::ControlModifier )
756 m_document->setZoom( e->delta() );
758 else
760 e->ignore();
764 void ThumbnailListPrivate::contextMenuEvent( QContextMenuEvent * e )
766 ThumbnailWidget* item = itemFor( e->pos() );
767 if ( item )
769 emit q->rightClick( item->page(), e->globalPos() );
773 void ThumbnailWidget::paint( QPainter &p, const QRect &_clipRect )
775 int width = m_pixmapWidth + m_margin;
776 QRect clipRect = _clipRect;
777 QPalette pal = m_parent->palette();
779 // draw the bottom label + highlight mark
780 QColor fillColor = m_selected ? pal.color( QPalette::Active, QPalette::Highlight ) : pal.color( QPalette::Active, QPalette::Base );
781 p.fillRect( clipRect, fillColor );
782 p.setPen( m_selected ? pal.color( QPalette::Active, QPalette::HighlightedText ) : pal.color( QPalette::Active, QPalette::Text ) );
783 p.drawText( 0, m_pixmapHeight + m_margin, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) );
785 // draw page outline and pixmap
786 if ( clipRect.top() < m_pixmapHeight + m_margin )
788 // if page is bookmarked draw a colored border
789 bool isBookmarked = m_parent->m_document->bookmarkManager()->isBookmarked( pageNumber() );
790 // draw the inner rect
791 p.setPen( isBookmarked ? QColor( 0xFF8000 ) : Qt::black );
792 p.drawRect( m_margin/2 - 1, m_margin/2 - 1, m_pixmapWidth + 1, m_pixmapHeight + 1 );
793 // draw the clear rect
794 p.setPen( isBookmarked ? QColor( 0x804000 ) : pal.color( QPalette::Active, QPalette::Base ) );
795 // draw the bottom and right shadow edges
796 if ( !isBookmarked )
798 int left, right, bottom, top;
799 left = m_margin/2 + 1;
800 right = m_margin/2 + m_pixmapWidth + 1;
801 bottom = m_pixmapHeight + m_margin/2 + 1;
802 top = m_margin/2 + 1;
803 p.setPen( Qt::gray );
804 p.drawLine( left, bottom, right, bottom );
805 p.drawLine( right, top, right, bottom );
808 // draw the page using the shared PagePainter class
809 p.translate( m_margin/2, m_margin/2 );
810 clipRect.translate( -m_margin/2, -m_margin/2 );
811 clipRect = clipRect.intersect( QRect( 0, 0, m_pixmapWidth, m_pixmapHeight ) );
812 if ( clipRect.isValid() )
814 int flags = PagePainter::Accessibility | PagePainter::Highlights |
815 PagePainter::Annotations;
816 PagePainter::paintPageOnPainter( &p, m_page, THUMBNAILS_ID, flags,
817 m_pixmapWidth, m_pixmapHeight, clipRect );
820 if ( !m_visibleRect.isNull() )
822 p.save();
823 p.setPen( QColor( 255, 255, 0, 200 ) );
824 p.setBrush( QColor( 0, 0, 0, 100 ) );
825 p.drawRect( m_visibleRect.geometry( m_pixmapWidth, m_pixmapHeight ).adjusted( 0, 0, -1, -1 ) );
826 p.restore();
829 // draw the bookmark overlay on the top-right corner
830 const QPixmap * bookmarkPixmap = m_parent->getBookmarkOverlay();
831 if ( isBookmarked && bookmarkPixmap )
833 int pixW = bookmarkPixmap->width(),
834 pixH = bookmarkPixmap->height();
835 clipRect = clipRect.intersect( QRect( m_pixmapWidth - pixW, 0, pixW, pixH ) );
836 if ( clipRect.isValid() )
837 p.drawPixmap( m_pixmapWidth - pixW, -pixH/8, *bookmarkPixmap );
843 /** ThumbnailsController implementation **/
845 #define FILTERB_ID 1
847 ThumbnailController::ThumbnailController( QWidget * parent, ThumbnailList * list )
848 : QToolBar( parent )
850 setObjectName( "ThumbsControlBar" );
851 // change toolbar appearance
852 setIconSize( QSize( 16, 16 ) );
853 setMovable( false );
854 QSizePolicy sp = sizePolicy();
855 sp.setVerticalPolicy( QSizePolicy::Minimum );
856 setSizePolicy( sp );
858 // insert a togglebutton [show only bookmarked pages]
859 //insertSeparator();
860 QAction * showBoomarkOnlyAction = addAction(
861 KIcon( "bookmarks" ), i18n( "Show bookmarked pages only" ) );
862 showBoomarkOnlyAction->setCheckable( true );
863 connect( showBoomarkOnlyAction, SIGNAL( toggled( bool ) ), list, SLOT( slotFilterBookmarks( bool ) ) );
864 showBoomarkOnlyAction->setChecked( Okular::Settings::filterBookmarks() );
865 //insertLineSeparator();
869 #include "thumbnaillist.moc"