|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a widget to select a PDF page to be shown. |
|
8 """ |
|
9 |
|
10 import contextlib |
|
11 |
|
12 from PyQt6.QtCore import Qt, pyqtSlot, pyqtSignal |
|
13 from PyQt6.QtGui import QIntValidator |
|
14 from PyQt6.QtPdf import QPdfDocument |
|
15 from PyQt6.QtWidgets import ( |
|
16 QToolButton, QHBoxLayout, QWidget, QLabel, QLineEdit |
|
17 ) |
|
18 |
|
19 from eric7.EricGui import EricPixmapCache |
|
20 |
|
21 |
|
22 class PdfPageSelector(QWidget): |
|
23 """ |
|
24 Class implementing a widget to select a PDF page to be shown. |
|
25 """ |
|
26 |
|
27 valueChanged = pyqtSignal(int) |
|
28 gotoPage = pyqtSignal() |
|
29 |
|
30 def __init__(self, parent=None): |
|
31 """ |
|
32 Constructor |
|
33 |
|
34 @param parent reference to the parent widget (defaults to None) |
|
35 @type QWidget (optional) |
|
36 """ |
|
37 super().__init__(parent) |
|
38 |
|
39 self.__document = None |
|
40 |
|
41 self.__prevButton = QToolButton(self) |
|
42 self.__prevButton.setIcon(EricPixmapCache.getIcon("1uparrow")) |
|
43 |
|
44 self.__nextButton = QToolButton(self) |
|
45 self.__nextButton.setIcon(EricPixmapCache.getIcon("1downarrow")) |
|
46 |
|
47 self.__pageButton = QToolButton() |
|
48 self.__pageButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextOnly) |
|
49 |
|
50 self.__pageEntry = QLineEdit() |
|
51 self.__pageEntry.setMaxLength(10) |
|
52 self.__pageEntry.setAlignment(Qt.AlignmentFlag.AlignCenter) |
|
53 self.__pageLabel = QLabel() |
|
54 |
|
55 self.__layout = QHBoxLayout() |
|
56 self.__layout.addWidget(self.__prevButton) |
|
57 self.__layout.addWidget(self.__pageEntry) |
|
58 self.__layout.addWidget(self.__pageLabel) |
|
59 self.__layout.addWidget(QLabel(self.tr("of"))) |
|
60 self.__layout.addWidget(self.__pageButton) |
|
61 self.__layout.addWidget(self.__nextButton) |
|
62 |
|
63 self.setLayout(self.__layout) |
|
64 |
|
65 # Setup signal/slot connections |
|
66 self.__prevButton.clicked.connect(self.__decrement) |
|
67 self.__nextButton.clicked.connect(self.__increment) |
|
68 self.__pageButton.clicked.connect(self.__pageButtonTriggered) |
|
69 self.__pageEntry.editingFinished.connect(self.__pageEntered) |
|
70 |
|
71 self.__initialize() |
|
72 |
|
73 def __initialize(self): |
|
74 """ |
|
75 Private method to initialize some internal state. |
|
76 """ |
|
77 self.__value = -1 |
|
78 self.__minimum = 0 |
|
79 self.__maximum = 0 |
|
80 |
|
81 self.__prevButton.setEnabled(False) |
|
82 self.__nextButton.setEnabled(False) |
|
83 self.__pageEntry.clear() |
|
84 self.__pageLabel.clear() |
|
85 self.__pageButton.setText(" ") |
|
86 |
|
87 self.setEnabled(False) |
|
88 |
|
89 def setDocument(self, document): |
|
90 """ |
|
91 Public method to set a reference to the associated PDF document. |
|
92 |
|
93 @param document reference to the associated PDF document |
|
94 @type QPdfDocument |
|
95 """ |
|
96 self.__document = document |
|
97 self.__document.statusChanged.connect(self.__documentStatusChanged) |
|
98 |
|
99 @pyqtSlot(int) |
|
100 def setValue(self, value): |
|
101 """ |
|
102 Public slot to set the value. |
|
103 |
|
104 Note: value is 0 based. |
|
105 |
|
106 @param value value to be set |
|
107 @type int |
|
108 """ |
|
109 if value != self.__value: |
|
110 with contextlib.suppress(RuntimeError): |
|
111 self.__pageEntry.setText(self.__document.pageLabel(value)) |
|
112 self.__pageLabel.setText(str(value + 1)) |
|
113 |
|
114 self.__value = value |
|
115 |
|
116 self.__prevButton.setEnabled(value > self.__minimum) |
|
117 self.__nextButton.setEnabled(value < self.__maximum) |
|
118 |
|
119 self.valueChanged.emit(value) |
|
120 |
|
121 def value(self): |
|
122 """ |
|
123 Public method to get the current value. |
|
124 |
|
125 @return current value |
|
126 @rtype int |
|
127 """ |
|
128 return self.__value |
|
129 |
|
130 def setMaximum(self, max): |
|
131 """ |
|
132 Public method to set the maximum value. |
|
133 |
|
134 Note: max is 0 based. |
|
135 |
|
136 @param max maximum value to be set |
|
137 @type int |
|
138 """ |
|
139 self.__maximum = max |
|
140 self.__nextButton.setEnabled(self.__value < self.__maximum) |
|
141 self.__pageButton.setText(str(max + 1)) |
|
142 |
|
143 @pyqtSlot() |
|
144 def __pageEntered(self): |
|
145 """ |
|
146 Private slot to handle the entering of a page value. |
|
147 """ |
|
148 model = self.__document.pageModel() |
|
149 start = model.index(0) |
|
150 indices = model.match( |
|
151 start, QPdfDocument.PageModelRole.Label.value, self.__pageEntry.text() |
|
152 ) |
|
153 if indices: |
|
154 self.setValue(indices[0].row()) |
|
155 else: |
|
156 # reset |
|
157 blocked = self.__pageEntry.blockSignals(True) |
|
158 self.__pageEntry.setText(self.__document.pageLabel(self.__value)) |
|
159 self.__pageEntry.blockSignals(blocked) |
|
160 |
|
161 @pyqtSlot() |
|
162 def __decrement(self): |
|
163 """ |
|
164 Private slot to decrement the current value. |
|
165 """ |
|
166 if self.__value > self.__minimum: |
|
167 self.setValue(self.__value - 1) |
|
168 |
|
169 @pyqtSlot() |
|
170 def __increment(self): |
|
171 """ |
|
172 Private slot to increment the current value. |
|
173 """ |
|
174 if self.__value < self.__maximum: |
|
175 self.setValue(self.__value + 1) |
|
176 |
|
177 @pyqtSlot() |
|
178 def __pageButtonTriggered(self): |
|
179 """ |
|
180 Private slot to handle the page button trigger. |
|
181 """ |
|
182 self.gotoPage.emit() |
|
183 |
|
184 @pyqtSlot(QPdfDocument.Status) |
|
185 def __documentStatusChanged(self, status): |
|
186 """ |
|
187 Private slot to handle a change of the document status. |
|
188 |
|
189 @param status current document status |
|
190 @type QPdfDocument.Status |
|
191 """ |
|
192 self.setEnabled(status == QPdfDocument.Status.Ready) |
|
193 if status == QPdfDocument.Status.Ready: |
|
194 numericalEntry = True |
|
195 # test the first page |
|
196 try: |
|
197 _ = int(self.__document.pageLabel(0)) |
|
198 except ValueError: |
|
199 numericalEntry = False |
|
200 # test the last page |
|
201 try: |
|
202 _ = int(self.__document.pageLabel(self.__document.pageCount() - 1)) |
|
203 except ValueError: |
|
204 numericalEntry = False |
|
205 self.__pageEntry.setValidator( |
|
206 QIntValidator(1, 99999) if numericalEntry else None |
|
207 ) |
|
208 self.__pageLabel.setVisible(not numericalEntry) |
|
209 elif status == QPdfDocument.Status.Null: |
|
210 self.__initialize() |