src/eric7/QtHelpInterface/HelpIndexWidget.py

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

eric ide

mercurial