src/eric7/WebBrowser/QtHelp/HelpIndexWidget.py

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

eric ide

mercurial