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") |