1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
# This file is part of the qpopplerview package.
#
# Copyright (c) 2010 - 2014 by Wilbert Berendsen
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# See http://www.gnu.org/licenses/ for more information.
"""
Provides an interface for paging in a View by page number.
"""
from PyQt5.QtCore import pyqtSignal, QEvent, QTimer, QObject
class Pager(QObject):
"""Provides an interface for paging in a View by page number.
Pages are numbered starting with 1 in this api!
"""
currentPageChanged = pyqtSignal(int)
pageCountChanged = pyqtSignal(int)
def __init__(self, view):
"""Initializes the Pager with the View.
Also connects with the Surface of the View and its Layout,
so don't interchange them after initializing the Pager.
"""
super(Pager, self).__init__(view)
self._currentPage = 0
self._pageCount = 0
self._blockLevel = 0
self._pageNumSet = False
self._updateTimer = QTimer(
singleShot=True, interval=100, timeout=self._updatePageNumber)
# connect
view.installEventFilter(self)
view.surface().installEventFilter(self)
view.surface().pageLayout().changed.connect(self._layoutChanged)
# Connect to the kineticScrollingEnabled signal to avoid unneeded updates.
view.kineticScrollingActive.connect(self.blockListening)
def currentPage(self):
"""Returns the current page number (0 if there are no pages)."""
return self._currentPage
def setCurrentPage(self, num):
"""Shows the specified page number."""
changed, self._currentPage = self._currentPage != num, num
self._pageNumSet = True
self.blockListening(True)
self.view().gotoPageNumber(num - 1)
self.blockListening(False)
if changed:
self.currentPageChanged.emit(self._currentPage)
def pageCount(self):
"""Returns the number of pages."""
return self._pageCount
def view(self):
return self.parent()
def _layoutChanged(self):
"""Called internally whenever the layout is updated."""
layout = self.view().surface().pageLayout()
self._pageCount, old = len(layout), self._pageCount
if old != self._pageCount:
self.pageCountChanged.emit(self._pageCount)
self._updatePageNumber()
def _updatePageNumber(self):
"""Called internally on layout change or view resize or surface move."""
self._currentPage, old = self.view().currentPageNumber() + 1, self._currentPage
if self._currentPage == 0 and self._pageCount > 0:
# the view may not be initialized
self._currentPage = 1
if old != self._currentPage:
self.currentPageChanged.emit(self._currentPage)
def blockListening(self, block):
"""Block/unblock listening to event, used to avoid multiple updates when we know lots
of events are going to be sent to the pager.
Blocking can be nested, only the outermost unblock will really unblock the event processing."""
if block:
self._blockLevel += 1
else:
self._blockLevel -= 1
if self._blockLevel == 0:
if self._pageNumSet:
self._pageNumSet = False
else:
self._updatePageNumber()
def eventFilter(self, obj, ev):
if (self._blockLevel == 0 and
((ev.type() == QEvent.Resize and obj is self.view())
or (ev.type() == QEvent.Move and obj is self.view().surface()))
and not self._updateTimer.isActive()):
self._updateTimer.start()
return False
|