eric7/WebBrowser/QtHelp/HelpIndexWidget.py

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

eric ide

mercurial