src/eric7/WebBrowser/Network/QtHelpSchemeHandler.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
8 """ 8 """
9 9
10 import mimetypes 10 import mimetypes
11 import os 11 import os
12 12
13 from PyQt6.QtCore import ( 13 from PyQt6.QtCore import pyqtSignal, QByteArray, QIODevice, QBuffer, QMutex
14 pyqtSignal, QByteArray, QIODevice, QBuffer, QMutex 14 from PyQt6.QtWebEngineCore import QWebEngineUrlSchemeHandler, QWebEngineUrlRequestJob
15 )
16 from PyQt6.QtWebEngineCore import (
17 QWebEngineUrlSchemeHandler, QWebEngineUrlRequestJob
18 )
19 15
20 from EricUtilities.EricMutexLocker import EricMutexLocker 16 from EricUtilities.EricMutexLocker import EricMutexLocker
21 17
22 QtDocPath = "qthelp://org.qt-project." 18 QtDocPath = "qthelp://org.qt-project."
23 19
56 52
57 class QtHelpSchemeHandler(QWebEngineUrlSchemeHandler): 53 class QtHelpSchemeHandler(QWebEngineUrlSchemeHandler):
58 """ 54 """
59 Class implementing a scheme handler for the qthelp: scheme. 55 Class implementing a scheme handler for the qthelp: scheme.
60 """ 56 """
57
61 def __init__(self, engine, parent=None): 58 def __init__(self, engine, parent=None):
62 """ 59 """
63 Constructor 60 Constructor
64 61
65 @param engine reference to the help engine 62 @param engine reference to the help engine
66 @type QHelpEngine 63 @type QHelpEngine
67 @param parent reference to the parent object 64 @param parent reference to the parent object
68 @type QObject 65 @type QObject
69 """ 66 """
70 super().__init__(parent) 67 super().__init__(parent)
71 68
72 self.__engine = engine 69 self.__engine = engine
73 70
74 self.__replies = [] 71 self.__replies = []
75 72
76 def requestStarted(self, job): 73 def requestStarted(self, job):
77 """ 74 """
78 Public method handling the URL request. 75 Public method handling the URL request.
79 76
80 @param job URL request job 77 @param job URL request job
81 @type QWebEngineUrlRequestJob 78 @type QWebEngineUrlRequestJob
82 """ 79 """
83 if job.requestUrl().scheme() == "qthelp": 80 if job.requestUrl().scheme() == "qthelp":
84 reply = QtHelpSchemeReply(job, self.__engine) 81 reply = QtHelpSchemeReply(job, self.__engine)
85 reply.closed.connect(lambda: self.__replyClosed(reply)) 82 reply.closed.connect(lambda: self.__replyClosed(reply))
86 self.__replies.append(reply) 83 self.__replies.append(reply)
87 job.reply(reply.mimeType(), reply) 84 job.reply(reply.mimeType(), reply)
88 else: 85 else:
89 job.fail(QWebEngineUrlRequestJob.Error.UrlInvalid) 86 job.fail(QWebEngineUrlRequestJob.Error.UrlInvalid)
90 87
91 def __replyClosed(self, reply): 88 def __replyClosed(self, reply):
92 """ 89 """
93 Private slot handling the closed signal of a reply. 90 Private slot handling the closed signal of a reply.
94 91
95 @param reply reference to the network reply 92 @param reply reference to the network reply
96 @type QtHelpSchemeReply 93 @type QtHelpSchemeReply
97 """ 94 """
98 if reply in self.__replies: 95 if reply in self.__replies:
99 self.__replies.remove(reply) 96 self.__replies.remove(reply)
100 97
101 98
102 class QtHelpSchemeReply(QIODevice): 99 class QtHelpSchemeReply(QIODevice):
103 """ 100 """
104 Class implementing a reply for a requested qthelp: page. 101 Class implementing a reply for a requested qthelp: page.
105 102
106 @signal closed emitted to signal that the web engine has read 103 @signal closed emitted to signal that the web engine has read
107 the data 104 the data
108 """ 105 """
106
109 closed = pyqtSignal() 107 closed = pyqtSignal()
110 108
111 def __init__(self, job, engine, parent=None): 109 def __init__(self, job, engine, parent=None):
112 """ 110 """
113 Constructor 111 Constructor
114 112
115 @param job reference to the URL request 113 @param job reference to the URL request
116 @type QWebEngineUrlRequestJob 114 @type QWebEngineUrlRequestJob
117 @param engine reference to the help engine 115 @param engine reference to the help engine
118 @type QHelpEngine 116 @type QHelpEngine
119 @param parent reference to the parent object 117 @param parent reference to the parent object
120 @type QObject 118 @type QObject
121 """ 119 """
122 super().__init__(parent) 120 super().__init__(parent)
123 121
124 self.__job = job 122 self.__job = job
125 self.__engine = engine 123 self.__engine = engine
126 self.__mutex = QMutex() 124 self.__mutex = QMutex()
127 125
128 self.__buffer = QBuffer() 126 self.__buffer = QBuffer()
129 127
130 # determine mimetype 128 # determine mimetype
131 url = self.__job.requestUrl() 129 url = self.__job.requestUrl()
132 strUrl = url.toString() 130 strUrl = url.toString()
133 131
134 # For some reason the url to load maybe wrong (passed from web engine) 132 # For some reason the url to load maybe wrong (passed from web engine)
135 # though the css file and the references inside should work that way. 133 # though the css file and the references inside should work that way.
136 # One possible problem might be that the css is loaded at the same 134 # One possible problem might be that the css is loaded at the same
137 # level as the html, thus a path inside the css like 135 # level as the html, thus a path inside the css like
138 # (../images/foo.png) might cd out of the virtual folder 136 # (../images/foo.png) might cd out of the virtual folder
139 if ( 137 if not self.__engine.findFile(url).isValid() and strUrl.startswith(QtDocPath):
140 not self.__engine.findFile(url).isValid() and
141 strUrl.startswith(QtDocPath)
142 ):
143 newUrl = self.__job.requestUrl() 138 newUrl = self.__job.requestUrl()
144 if not newUrl.path().startswith("/qdoc/"): 139 if not newUrl.path().startswith("/qdoc/"):
145 newUrl.setPath("/qdoc" + newUrl.path()) 140 newUrl.setPath("/qdoc" + newUrl.path())
146 url = newUrl 141 url = newUrl
147 strUrl = url.toString() 142 strUrl = url.toString()
148 143
149 self.__mimeType = mimetypes.guess_type(strUrl)[0] 144 self.__mimeType = mimetypes.guess_type(strUrl)[0]
150 if self.__mimeType is None: 145 if self.__mimeType is None:
151 # do our own (limited) guessing 146 # do our own (limited) guessing
152 self.__mimeType = self.__mimeFromUrl(url) 147 self.__mimeType = self.__mimeFromUrl(url)
153 148
154 self.__loadQtHelpPage(url) 149 self.__loadQtHelpPage(url)
155 150
156 def __loadQtHelpPage(self, url): 151 def __loadQtHelpPage(self, url):
157 """ 152 """
158 Private method to load the requested QtHelp page. 153 Private method to load the requested QtHelp page.
159 154
160 @param url URL of the requested page 155 @param url URL of the requested page
161 @type QUrl 156 @type QUrl
162 """ 157 """
163 data = ( 158 data = (
164 self.__engine.fileData(url) 159 self.__engine.fileData(url)
165 if self.__engine.findFile(url).isValid() else 160 if self.__engine.findFile(url).isValid()
166 QByteArray(self.tr( 161 else QByteArray(
167 """<html>""" 162 self.tr(
168 """<head><title>Error 404...</title></head>""" 163 """<html>"""
169 """<body><div align="center"><br><br>""" 164 """<head><title>Error 404...</title></head>"""
170 """<h1>The page could not be found</h1><br>""" 165 """<body><div align="center"><br><br>"""
171 """<h3>'{0}'</h3></div></body>""" 166 """<h1>The page could not be found</h1><br>"""
172 """</html>""").format(url.toString()) 167 """<h3>'{0}'</h3></div></body>"""
173 .encode("utf-8")) 168 """</html>"""
169 )
170 .format(url.toString())
171 .encode("utf-8")
172 )
174 ) 173 )
175 174
176 with EricMutexLocker(self.__mutex): 175 with EricMutexLocker(self.__mutex):
177 self.__buffer.setData(data) 176 self.__buffer.setData(data)
178 self.__buffer.open(QIODevice.OpenModeFlag.ReadOnly) 177 self.__buffer.open(QIODevice.OpenModeFlag.ReadOnly)
179 self.open(QIODevice.OpenModeFlag.ReadOnly) 178 self.open(QIODevice.OpenModeFlag.ReadOnly)
180 179
181 self.readyRead.emit() 180 self.readyRead.emit()
182 181
183 def bytesAvailable(self): 182 def bytesAvailable(self):
184 """ 183 """
185 Public method to get the number of available bytes. 184 Public method to get the number of available bytes.
186 185
187 @return number of available bytes 186 @return number of available bytes
188 @rtype int 187 @rtype int
189 """ 188 """
190 with EricMutexLocker(self.__mutex): 189 with EricMutexLocker(self.__mutex):
191 return self.__buffer.bytesAvailable() 190 return self.__buffer.bytesAvailable()
192 191
193 def readData(self, maxlen): 192 def readData(self, maxlen):
194 """ 193 """
195 Public method to retrieve data from the reply object. 194 Public method to retrieve data from the reply object.
196 195
197 @param maxlen maximum number of bytes to read (integer) 196 @param maxlen maximum number of bytes to read (integer)
198 @return string containing the data (bytes) 197 @return string containing the data (bytes)
199 """ 198 """
200 with EricMutexLocker(self.__mutex): 199 with EricMutexLocker(self.__mutex):
201 return self.__buffer.read(maxlen) 200 return self.__buffer.read(maxlen)
202 201
203 def close(self): 202 def close(self):
204 """ 203 """
205 Public method used to cloase the reply. 204 Public method used to cloase the reply.
206 """ 205 """
207 super().close() 206 super().close()
208 self.closed.emit() 207 self.closed.emit()
209 208
210 def __mimeFromUrl(self, url): 209 def __mimeFromUrl(self, url):
211 """ 210 """
212 Private method to guess the mime type given an URL. 211 Private method to guess the mime type given an URL.
213 212
214 @param url URL to guess the mime type from (QUrl) 213 @param url URL to guess the mime type from (QUrl)
215 @return mime type for the given URL (string) 214 @return mime type for the given URL (string)
216 """ 215 """
217 path = url.path() 216 path = url.path()
218 ext = os.path.splitext(path)[1].lower() 217 ext = os.path.splitext(path)[1].lower()
219 if ext in ExtensionMap: 218 if ext in ExtensionMap:
220 return ExtensionMap[ext] 219 return ExtensionMap[ext]
221 else: 220 else:
222 return "application/octet-stream" 221 return "application/octet-stream"
223 222
224 def mimeType(self): 223 def mimeType(self):
225 """ 224 """
226 Public method to get the reply mime type. 225 Public method to get the reply mime type.
227 226
228 @return mime type of the reply 227 @return mime type of the reply
229 @rtype bytes 228 @rtype bytes
230 """ 229 """
231 return self.__mimeType.encode("utf-8") 230 return self.__mimeType.encode("utf-8")

eric ide

mercurial