src/eric7/WebBrowser/QtHelp/HelpIndexWidget.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9473
3f23dbf37dbe
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl, QEvent 10 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl, QEvent
11 from PyQt6.QtGui import QGuiApplication, QClipboard 11 from PyQt6.QtGui import QGuiApplication, QClipboard
12 from PyQt6.QtHelp import QHelpLink 12 from PyQt6.QtHelp import QHelpLink
13 from PyQt6.QtWidgets import ( 13 from PyQt6.QtWidgets import (
14 QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QMenu, QDialog, 14 QWidget,
15 QApplication 15 QVBoxLayout,
16 QHBoxLayout,
17 QLabel,
18 QLineEdit,
19 QMenu,
20 QDialog,
21 QApplication,
16 ) 22 )
17 23
18 24
19 class HelpIndexWidget(QWidget): 25 class HelpIndexWidget(QWidget):
20 """ 26 """
21 Class implementing a window for showing the QtHelp index. 27 Class implementing a window for showing the QtHelp index.
22 28
23 @signal escapePressed() emitted when the ESC key was pressed 29 @signal escapePressed() emitted when the ESC key was pressed
24 @signal openUrl(QUrl, str) emitted to open an entry in the current tab 30 @signal openUrl(QUrl, str) emitted to open an entry in the current tab
25 @signal newTab(QUrl, str) emitted to open an entry in a new tab 31 @signal newTab(QUrl, str) emitted to open an entry in a new tab
26 @signal newBackgroundTab(QUrl, str) emitted to open an entry in a 32 @signal newBackgroundTab(QUrl, str) emitted to open an entry in a
27 new background tab 33 new background tab
28 @signal newWindow(QUrl, str) emitted to open an entry in a new window 34 @signal newWindow(QUrl, str) emitted to open an entry in a new window
29 """ 35 """
36
30 escapePressed = pyqtSignal() 37 escapePressed = pyqtSignal()
31 openUrl = pyqtSignal(QUrl) 38 openUrl = pyqtSignal(QUrl)
32 newTab = pyqtSignal(QUrl) 39 newTab = pyqtSignal(QUrl)
33 newBackgroundTab = pyqtSignal(QUrl) 40 newBackgroundTab = pyqtSignal(QUrl)
34 newWindow = pyqtSignal(QUrl) 41 newWindow = pyqtSignal(QUrl)
35 42
36 def __init__(self, engine, internal=False, parent=None): 43 def __init__(self, engine, internal=False, parent=None):
37 """ 44 """
38 Constructor 45 Constructor
39 46
40 @param engine reference to the help engine 47 @param engine reference to the help engine
41 @type QHelpEngine 48 @type QHelpEngine
42 @param internal flag indicating the internal help viewer 49 @param internal flag indicating the internal help viewer
43 @type bool 50 @type bool
44 @param parent reference to the parent widget 51 @param parent reference to the parent widget
45 @type QWidget 52 @type QWidget
46 """ 53 """
47 super().__init__(parent) 54 super().__init__(parent)
48 55
49 self.__engine = engine 56 self.__engine = engine
50 self.__internal = internal 57 self.__internal = internal
51 58
52 self.__searchEdit = None 59 self.__searchEdit = None
53 self.__index = None 60 self.__index = None
54 61
55 self.__layout = QVBoxLayout(self) 62 self.__layout = QVBoxLayout(self)
56 if internal: 63 if internal:
57 # no margins for the internal variant 64 # no margins for the internal variant
58 self.__layout.setContentsMargins(0, 0, 0, 0) 65 self.__layout.setContentsMargins(0, 0, 0, 0)
59 66
60 self.__searchEditLayout = QHBoxLayout() 67 self.__searchEditLayout = QHBoxLayout()
61 label = QLabel(self.tr("&Look for:")) 68 label = QLabel(self.tr("&Look for:"))
62 self.__searchEditLayout.addWidget(label) 69 self.__searchEditLayout.addWidget(label)
63 70
64 self.__searchEdit = QLineEdit() 71 self.__searchEdit = QLineEdit()
65 self.__searchEdit.setClearButtonEnabled(True) 72 self.__searchEdit.setClearButtonEnabled(True)
66 label.setBuddy(self.__searchEdit) 73 label.setBuddy(self.__searchEdit)
67 self.__searchEdit.textChanged.connect(self.__filterIndices) 74 self.__searchEdit.textChanged.connect(self.__filterIndices)
68 self.__searchEdit.installEventFilter(self) 75 self.__searchEdit.installEventFilter(self)
69 self.__searchEditLayout.addWidget(self.__searchEdit) 76 self.__searchEditLayout.addWidget(self.__searchEdit)
70 self.__layout.addLayout(self.__searchEditLayout) 77 self.__layout.addLayout(self.__searchEditLayout)
71 78
72 self.__index = self.__engine.indexWidget() 79 self.__index = self.__engine.indexWidget()
73 self.__index.setContextMenuPolicy( 80 self.__index.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
74 Qt.ContextMenuPolicy.CustomContextMenu) 81
75
76 self.__engine.indexModel().indexCreationStarted.connect( 82 self.__engine.indexModel().indexCreationStarted.connect(
77 self.__disableSearchEdit) 83 self.__disableSearchEdit
78 self.__engine.indexModel().indexCreated.connect( 84 )
79 self.__enableSearchEdit) 85 self.__engine.indexModel().indexCreated.connect(self.__enableSearchEdit)
80 self.__index.documentActivated.connect(self.__documentActivated) 86 self.__index.documentActivated.connect(self.__documentActivated)
81 self.__index.documentsActivated.connect(self.__documentsActivated) 87 self.__index.documentsActivated.connect(self.__documentsActivated)
82 self.__index.customContextMenuRequested.connect( 88 self.__index.customContextMenuRequested.connect(self.__showContextMenu)
83 self.__showContextMenu) 89 self.__searchEdit.returnPressed.connect(self.__index.activateCurrentItem)
84 self.__searchEdit.returnPressed.connect(
85 self.__index.activateCurrentItem)
86 self.__layout.addWidget(self.__index) 90 self.__layout.addWidget(self.__index)
87 91
88 @pyqtSlot(QHelpLink, str) 92 @pyqtSlot(QHelpLink, str)
89 def __documentActivated(self, document, keyword, modifiers=None): 93 def __documentActivated(self, document, keyword, modifiers=None):
90 """ 94 """
91 Private slot to handle the activation of a keyword entry. 95 Private slot to handle the activation of a keyword entry.
92 96
93 @param document reference to a data structure containing the 97 @param document reference to a data structure containing the
94 document info 98 document info
95 @type QHelpLink 99 @type QHelpLink
96 @param keyword keyword for the URL 100 @param keyword keyword for the URL
97 @type str 101 @type str
100 """ 104 """
101 if modifiers is None: 105 if modifiers is None:
102 modifiers = QApplication.keyboardModifiers() 106 modifiers = QApplication.keyboardModifiers()
103 if not document.url.isEmpty() and document.url.isValid(): 107 if not document.url.isEmpty() and document.url.isValid():
104 if modifiers & ( 108 if modifiers & (
105 Qt.KeyboardModifier.ControlModifier |
106 Qt.KeyboardModifier.ControlModifier 109 Qt.KeyboardModifier.ControlModifier
110 | Qt.KeyboardModifier.ControlModifier
107 ): 111 ):
108 self.newBackgroundTab.emit(document.url) 112 self.newBackgroundTab.emit(document.url)
109 elif modifiers & Qt.KeyboardModifier.ControlModifier: 113 elif modifiers & Qt.KeyboardModifier.ControlModifier:
110 self.newTab.emit(document.url) 114 self.newTab.emit(document.url)
111 elif ( 115 elif modifiers & Qt.KeyboardModifier.ShiftModifier and not self.__internal:
112 modifiers & Qt.KeyboardModifier.ShiftModifier and
113 not self.__internal
114 ):
115 self.newWindow.emit(document.url) 116 self.newWindow.emit(document.url)
116 else: 117 else:
117 self.openUrl.emit(document.url) 118 self.openUrl.emit(document.url)
118 119
119 def __documentsActivated(self, documents, helpKeyword): 120 def __documentsActivated(self, documents, helpKeyword):
120 """ 121 """
121 Private slot to handle the activation of an entry with multiple help 122 Private slot to handle the activation of an entry with multiple help
122 documents. 123 documents.
123 124
124 @param documents list of help document link data structures 125 @param documents list of help document link data structures
125 @type list of QHelpLink 126 @type list of QHelpLink
126 @param helpKeyword keyword for the entry 127 @param helpKeyword keyword for the entry
127 @type str 128 @type str
128 """ 129 """
129 modifiers = QApplication.keyboardModifiers() 130 modifiers = QApplication.keyboardModifiers()
130 document = ( 131 document = (
131 documents[0] 132 documents[0]
132 if len(documents) == 1 else 133 if len(documents) == 1
133 self.__selectDocument(documents, helpKeyword) 134 else self.__selectDocument(documents, helpKeyword)
134 ) 135 )
135 self.__documentActivated(document, helpKeyword, modifiers) 136 self.__documentActivated(document, helpKeyword, modifiers)
136 137
137 def __selectDocument(self, documents, helpKeyword): 138 def __selectDocument(self, documents, helpKeyword):
138 """ 139 """
139 Private method to give the user a chance to select among the 140 Private method to give the user a chance to select among the
140 given documents. 141 given documents.
141 142
142 @param documents list of help document link data structures 143 @param documents list of help document link data structures
143 @type list of QHelpLink 144 @type list of QHelpLink
144 @param helpKeyword keyword for the documents 145 @param helpKeyword keyword for the documents
145 @type str 146 @type str
146 @return selected document 147 @return selected document
147 @rtype QHelpLink 148 @rtype QHelpLink
148 """ 149 """
149 document = QHelpLink() 150 document = QHelpLink()
150 151
151 from .HelpTopicDialog import HelpTopicDialog 152 from .HelpTopicDialog import HelpTopicDialog
153
152 dlg = HelpTopicDialog(self, helpKeyword, documents) 154 dlg = HelpTopicDialog(self, helpKeyword, documents)
153 if dlg.exec() == QDialog.DialogCode.Accepted: 155 if dlg.exec() == QDialog.DialogCode.Accepted:
154 document = dlg.document() 156 document = dlg.document()
155 157
156 return document 158 return document
157 159
158 def __filterIndices(self, indexFilter): 160 def __filterIndices(self, indexFilter):
159 """ 161 """
160 Private slot to filter the indexes according to the given filter. 162 Private slot to filter the indexes according to the given filter.
161 163
162 @param indexFilter filter to be used 164 @param indexFilter filter to be used
163 @type str 165 @type str
164 """ 166 """
165 if '*' in indexFilter: 167 if "*" in indexFilter:
166 self.__index.filterIndices(indexFilter, indexFilter) 168 self.__index.filterIndices(indexFilter, indexFilter)
167 else: 169 else:
168 self.__index.filterIndices(indexFilter) 170 self.__index.filterIndices(indexFilter)
169 171
170 def __enableSearchEdit(self): 172 def __enableSearchEdit(self):
171 """ 173 """
172 Private slot to enable the search edit. 174 Private slot to enable the search edit.
173 """ 175 """
174 self.__searchEdit.setEnabled(True) 176 self.__searchEdit.setEnabled(True)
175 self.__filterIndices(self.__searchEdit.text()) 177 self.__filterIndices(self.__searchEdit.text())
176 178
177 def __disableSearchEdit(self): 179 def __disableSearchEdit(self):
178 """ 180 """
179 Private slot to enable the search edit. 181 Private slot to enable the search edit.
180 """ 182 """
181 self.__searchEdit.setEnabled(False) 183 self.__searchEdit.setEnabled(False)
182 184
183 def focusInEvent(self, evt): 185 def focusInEvent(self, evt):
184 """ 186 """
185 Protected method handling focus in events. 187 Protected method handling focus in events.
186 188
187 @param evt reference to the focus event object 189 @param evt reference to the focus event object
188 @type QFocusEvent 190 @type QFocusEvent
189 """ 191 """
190 if evt.reason() != Qt.FocusReason.MouseFocusReason: 192 if evt.reason() != Qt.FocusReason.MouseFocusReason:
191 self.__searchEdit.selectAll() 193 self.__searchEdit.selectAll()
192 self.__searchEdit.setFocus() 194 self.__searchEdit.setFocus()
193 195
194 def eventFilter(self, watched, event): 196 def eventFilter(self, watched, event):
195 """ 197 """
196 Public method called to filter the event queue. 198 Public method called to filter the event queue.
197 199
198 @param watched the QObject being watched 200 @param watched the QObject being watched
199 @type QObject 201 @type QObject
200 @param event the event that occurred 202 @param event the event that occurred
201 @type QEvent 203 @type QEvent
202 @return flag indicating whether the event was handled 204 @return flag indicating whether the event was handled
203 @rtype bool 205 @rtype bool
204 """ 206 """
205 if ( 207 if (
206 self.__searchEdit and watched == self.__searchEdit and 208 self.__searchEdit
207 event.type() == QEvent.Type.KeyPress 209 and watched == self.__searchEdit
210 and event.type() == QEvent.Type.KeyPress
208 ): 211 ):
209 idx = self.__index.currentIndex() 212 idx = self.__index.currentIndex()
210 if event.key() == Qt.Key.Key_Up: 213 if event.key() == Qt.Key.Key_Up:
211 idx = self.__index.model().index( 214 idx = self.__index.model().index(
212 idx.row() - 1, idx.column(), idx.parent()) 215 idx.row() - 1, idx.column(), idx.parent()
216 )
213 if idx.isValid(): 217 if idx.isValid():
214 self.__index.setCurrentIndex(idx) 218 self.__index.setCurrentIndex(idx)
215 elif event.key() == Qt.Key.Key_Down: 219 elif event.key() == Qt.Key.Key_Down:
216 idx = self.__index.model().index( 220 idx = self.__index.model().index(
217 idx.row() + 1, idx.column(), idx.parent()) 221 idx.row() + 1, idx.column(), idx.parent()
222 )
218 if idx.isValid(): 223 if idx.isValid():
219 self.__index.setCurrentIndex(idx) 224 self.__index.setCurrentIndex(idx)
220 elif event.key() == Qt.Key.Key_Escape: 225 elif event.key() == Qt.Key.Key_Escape:
221 self.escapePressed.emit() 226 self.escapePressed.emit()
222 227
223 return QWidget.eventFilter(self, watched, event) 228 return QWidget.eventFilter(self, watched, event)
224 229
225 def __showContextMenu(self, pos): 230 def __showContextMenu(self, pos):
226 """ 231 """
227 Private slot showing the context menu. 232 Private slot showing the context menu.
228 233
229 @param pos position to show the menu at 234 @param pos position to show the menu at
230 @type QPoint 235 @type QPoint
231 """ 236 """
232 idx = self.__index.indexAt(pos) 237 idx = self.__index.indexAt(pos)
233 if idx.isValid(): 238 if idx.isValid():
234 menu = QMenu() 239 menu = QMenu()
235 curTab = menu.addAction(self.tr("Open Link")) 240 curTab = menu.addAction(self.tr("Open Link"))
236 if self.__internal: 241 if self.__internal:
237 newTab = menu.addAction(self.tr("Open Link in New Page")) 242 newTab = menu.addAction(self.tr("Open Link in New Page"))
238 newBackgroundTab = menu.addAction( 243 newBackgroundTab = menu.addAction(
239 self.tr("Open Link in Background Page")) 244 self.tr("Open Link in Background Page")
245 )
240 else: 246 else:
241 newTab = menu.addAction(self.tr("Open Link in New Tab")) 247 newTab = menu.addAction(self.tr("Open Link in New Tab"))
242 newBackgroundTab = menu.addAction( 248 newBackgroundTab = menu.addAction(
243 self.tr("Open Link in Background Tab")) 249 self.tr("Open Link in Background Tab")
250 )
244 newWindow = menu.addAction(self.tr("Open Link in New Window")) 251 newWindow = menu.addAction(self.tr("Open Link in New Window"))
245 menu.addSeparator() 252 menu.addSeparator()
246 copyLink = menu.addAction(self.tr("Copy URL to Clipboard")) 253 copyLink = menu.addAction(self.tr("Copy URL to Clipboard"))
247 menu.move(self.__index.mapToGlobal(pos)) 254 menu.move(self.__index.mapToGlobal(pos))
248 255
249 act = menu.exec() 256 act = menu.exec()
250 model = self.__index.model() 257 model = self.__index.model()
251 if model is not None: 258 if model is not None:
252 helpKeyword = model.data(idx, Qt.ItemDataRole.DisplayRole) 259 helpKeyword = model.data(idx, Qt.ItemDataRole.DisplayRole)
253 helpLinks = self.__engine.documentsForKeyword(helpKeyword, "") 260 helpLinks = self.__engine.documentsForKeyword(helpKeyword, "")
254 if len(helpLinks) == 1: 261 if len(helpLinks) == 1:
255 link = helpLinks[0].url 262 link = helpLinks[0].url
256 else: 263 else:
257 link = self.__selectDocument(helpLinks, helpKeyword).url 264 link = self.__selectDocument(helpLinks, helpKeyword).url
258 265
259 if not link.isEmpty() and link.isValid(): 266 if not link.isEmpty() and link.isValid():
260 if act == curTab: 267 if act == curTab:
261 self.openUrl.emit(link) 268 self.openUrl.emit(link)
262 elif act == newTab: 269 elif act == newTab:
263 self.newTab.emit(link) 270 self.newTab.emit(link)
266 elif not self.__internal and act == newWindow: 273 elif not self.__internal and act == newWindow:
267 self.newWindow.emit(link) 274 self.newWindow.emit(link)
268 elif act == copyLink: 275 elif act == copyLink:
269 # copy the URL to both clipboard areas 276 # copy the URL to both clipboard areas
270 QGuiApplication.clipboard().setText( 277 QGuiApplication.clipboard().setText(
271 link.toString(), QClipboard.Mode.Clipboard) 278 link.toString(), QClipboard.Mode.Clipboard
279 )
272 QGuiApplication.clipboard().setText( 280 QGuiApplication.clipboard().setText(
273 link.toString(), QClipboard.Mode.Selection) 281 link.toString(), QClipboard.Mode.Selection
282 )

eric ide

mercurial