21 |
21 |
22 class HelpDocsInstaller(QThread): |
22 class HelpDocsInstaller(QThread): |
23 """ |
23 """ |
24 Class implementing the worker thread populating and updating the QtHelp |
24 Class implementing the worker thread populating and updating the QtHelp |
25 documentation database. |
25 documentation database. |
26 |
26 |
27 @signal errorMessage(str) emitted, if an error occurred during |
27 @signal errorMessage(str) emitted, if an error occurred during |
28 the installation of the documentation |
28 the installation of the documentation |
29 @signal docsInstalled(bool) emitted after the installation has finished |
29 @signal docsInstalled(bool) emitted after the installation has finished |
30 """ |
30 """ |
|
31 |
31 errorMessage = pyqtSignal(str) |
32 errorMessage = pyqtSignal(str) |
32 docsInstalled = pyqtSignal(bool) |
33 docsInstalled = pyqtSignal(bool) |
33 |
34 |
34 def __init__(self, collection): |
35 def __init__(self, collection): |
35 """ |
36 """ |
36 Constructor |
37 Constructor |
37 |
38 |
38 @param collection full pathname of the collection file |
39 @param collection full pathname of the collection file |
39 @type str |
40 @type str |
40 """ |
41 """ |
41 super().__init__() |
42 super().__init__() |
42 |
43 |
43 self.__abort = False |
44 self.__abort = False |
44 self.__collection = collection |
45 self.__collection = collection |
45 self.__mutex = QMutex() |
46 self.__mutex = QMutex() |
46 |
47 |
47 def stop(self): |
48 def stop(self): |
48 """ |
49 """ |
49 Public slot to stop the installation procedure. |
50 Public slot to stop the installation procedure. |
50 """ |
51 """ |
51 if not self.isRunning(): |
52 if not self.isRunning(): |
52 return |
53 return |
53 |
54 |
54 self.__mutex.lock() |
55 self.__mutex.lock() |
55 self.__abort = True |
56 self.__abort = True |
56 self.__mutex.unlock() |
57 self.__mutex.unlock() |
57 self.wait() |
58 self.wait() |
58 |
59 |
59 def installDocs(self): |
60 def installDocs(self): |
60 """ |
61 """ |
61 Public method to start the installation procedure. |
62 Public method to start the installation procedure. |
62 """ |
63 """ |
63 self.start(QThread.Priority.LowPriority) |
64 self.start(QThread.Priority.LowPriority) |
64 |
65 |
65 def run(self): |
66 def run(self): |
66 """ |
67 """ |
67 Public method executed by the thread. |
68 Public method executed by the thread. |
68 """ |
69 """ |
69 engine = QHelpEngineCore(self.__collection) |
70 engine = QHelpEngineCore(self.__collection) |
70 changes = False |
71 changes = False |
71 |
72 |
72 qt5Docs = [ |
73 qt5Docs = [ |
73 "activeqt", "qdoc", "qmake", "qt3d", "qt3drenderer", |
74 "activeqt", |
74 "qtandroidextras", "qtassistant", "qtbluetooth", "qtcanvas3d", |
75 "qdoc", |
75 "qtcharts", "qtcmake", "qtconcurrent", "qtcore", "qtdatavis3d", |
76 "qmake", |
76 "qtdatavisualization", "qtdbus", "qtdesigner", |
77 "qt3d", |
77 "qtdistancefieldgenerator", "qtdoc", "qtenginio", |
78 "qt3drenderer", |
78 "qtenginiooverview", "qtenginoqml", "qtgamepad", |
79 "qtandroidextras", |
79 "qtgraphicaleffects", "qtgui", "qthelp", "qtimageformats", |
80 "qtassistant", |
80 "qtlabscalendar", "qtlabsplatform", "qtlabscontrols", "qtlinguist", |
81 "qtbluetooth", |
81 "qtlocation", "qtlottieanimation", "qtmaxextras", "qtmultimedia", |
82 "qtcanvas3d", |
82 "qtmultimediawidgets", "qtnetwork", "qtnetworkauth", "qtnfc", |
83 "qtcharts", |
83 "qtopengl", "qtplatformheaders", "qtpositioning", "qtprintsupport", |
84 "qtcmake", |
84 "qtpurchasing", "qtqml", "qtqmlmodels", "qtqmltest", "qtquick", |
85 "qtconcurrent", |
85 "qtquick3d", "qtquickcontrols", "qtquickcontrols1", |
86 "qtcore", |
86 "qtquickdialogs", "qtquickextras", "qtquicklayouts", |
87 "qtdatavis3d", |
87 "qtquicktimeline", "qtremoteobjects", "qtscript", "qtscripttools", |
88 "qtdatavisualization", |
88 "qtscxml", "qtsensors", "qtserialbus", "qtserialport", |
89 "qtdbus", |
89 "qtshadertools", "qtspeech", "qtsql", "qtsvg", "qttest", |
90 "qtdesigner", |
90 "qttestlib", "qtuitools", "qtvirtualkeyboard", |
91 "qtdistancefieldgenerator", |
91 "qtwaylandcompositor", "qtwebchannel", "qtwebengine", |
92 "qtdoc", |
92 "qtwebenginewidgets", "qtwebkit", "qtwebkitexamples", |
93 "qtenginio", |
93 "qtwebsockets", "qtwebview", "qtwidgets", "qtwinextras", |
94 "qtenginiooverview", |
94 "qtx11extras", "qtxml", "qtxmlpatterns"] |
95 "qtenginoqml", |
|
96 "qtgamepad", |
|
97 "qtgraphicaleffects", |
|
98 "qtgui", |
|
99 "qthelp", |
|
100 "qtimageformats", |
|
101 "qtlabscalendar", |
|
102 "qtlabsplatform", |
|
103 "qtlabscontrols", |
|
104 "qtlinguist", |
|
105 "qtlocation", |
|
106 "qtlottieanimation", |
|
107 "qtmaxextras", |
|
108 "qtmultimedia", |
|
109 "qtmultimediawidgets", |
|
110 "qtnetwork", |
|
111 "qtnetworkauth", |
|
112 "qtnfc", |
|
113 "qtopengl", |
|
114 "qtplatformheaders", |
|
115 "qtpositioning", |
|
116 "qtprintsupport", |
|
117 "qtpurchasing", |
|
118 "qtqml", |
|
119 "qtqmlmodels", |
|
120 "qtqmltest", |
|
121 "qtquick", |
|
122 "qtquick3d", |
|
123 "qtquickcontrols", |
|
124 "qtquickcontrols1", |
|
125 "qtquickdialogs", |
|
126 "qtquickextras", |
|
127 "qtquicklayouts", |
|
128 "qtquicktimeline", |
|
129 "qtremoteobjects", |
|
130 "qtscript", |
|
131 "qtscripttools", |
|
132 "qtscxml", |
|
133 "qtsensors", |
|
134 "qtserialbus", |
|
135 "qtserialport", |
|
136 "qtshadertools", |
|
137 "qtspeech", |
|
138 "qtsql", |
|
139 "qtsvg", |
|
140 "qttest", |
|
141 "qttestlib", |
|
142 "qtuitools", |
|
143 "qtvirtualkeyboard", |
|
144 "qtwaylandcompositor", |
|
145 "qtwebchannel", |
|
146 "qtwebengine", |
|
147 "qtwebenginewidgets", |
|
148 "qtwebkit", |
|
149 "qtwebkitexamples", |
|
150 "qtwebsockets", |
|
151 "qtwebview", |
|
152 "qtwidgets", |
|
153 "qtwinextras", |
|
154 "qtx11extras", |
|
155 "qtxml", |
|
156 "qtxmlpatterns", |
|
157 ] |
95 for qtDocs, version in [(qt5Docs, 5)]: |
158 for qtDocs, version in [(qt5Docs, 5)]: |
96 for doc in qtDocs: |
159 for doc in qtDocs: |
97 changes |= self.__installQtDoc(doc, version, engine) |
160 changes |= self.__installQtDoc(doc, version, engine) |
98 self.__mutex.lock() |
161 self.__mutex.lock() |
99 if self.__abort: |
162 if self.__abort: |
100 engine = None |
163 engine = None |
101 self.__mutex.unlock() |
164 self.__mutex.unlock() |
102 return |
165 return |
103 self.__mutex.unlock() |
166 self.__mutex.unlock() |
104 |
167 |
105 changes |= self.__installEric7Doc(engine) |
168 changes |= self.__installEric7Doc(engine) |
106 engine = None |
169 engine = None |
107 del engine |
170 del engine |
108 self.docsInstalled.emit(changes) |
171 self.docsInstalled.emit(changes) |
109 |
172 |
110 def __installQtDoc(self, name, version, engine): |
173 def __installQtDoc(self, name, version, engine): |
111 """ |
174 """ |
112 Private method to install/update a Qt help document. |
175 Private method to install/update a Qt help document. |
113 |
176 |
114 @param name name of the Qt help document |
177 @param name name of the Qt help document |
115 @type str |
178 @type str |
116 @param version Qt version of the help documents |
179 @param version Qt version of the help documents |
117 @type int |
180 @type int |
118 @param engine reference to the help engine |
181 @param engine reference to the help engine |
120 @return flag indicating success |
183 @return flag indicating success |
121 @rtype bool |
184 @rtype bool |
122 """ |
185 """ |
123 versionKey = "qt_version_{0}@@{1}".format(version, name) |
186 versionKey = "qt_version_{0}@@{1}".format(version, name) |
124 info = engine.customValue(versionKey, "") |
187 info = engine.customValue(versionKey, "") |
125 lst = info.split('|') |
188 lst = info.split("|") |
126 |
189 |
127 dt = None |
190 dt = None |
128 if len(lst) and lst[0]: |
191 if len(lst) and lst[0]: |
129 dt = datetime.datetime.fromisoformat(lst[0]) |
192 dt = datetime.datetime.fromisoformat(lst[0]) |
130 |
193 |
131 qchFile = "" |
194 qchFile = "" |
132 if len(lst) == 2: |
195 if len(lst) == 2: |
133 qchFile = lst[1] |
196 qchFile = lst[1] |
134 |
197 |
135 if version == 5: |
198 if version == 5: |
136 docsPath = pathlib.Path(QLibraryInfo.path( |
199 docsPath = pathlib.Path( |
137 QLibraryInfo.LibraryPath.DocumentationPath)) |
200 QLibraryInfo.path(QLibraryInfo.LibraryPath.DocumentationPath) |
138 if ( |
201 ) |
139 not docsPath.is_dir() or |
202 if not docsPath.is_dir() or len(docsPath.glob("*.qch")) == 0: |
140 len(docsPath.glob("*.qch")) == 0 |
|
141 ): |
|
142 docsPath = ( |
203 docsPath = ( |
143 docsPath.parents[2] / "Docs" / |
204 docsPath.parents[2] / "Docs" / "Qt-{0}.{1}".format(*qVersionTuple()) |
144 "Qt-{0}.{1}".format(*qVersionTuple()) |
|
145 ) |
205 ) |
146 else: |
206 else: |
147 # unsupported Qt version |
207 # unsupported Qt version |
148 return False |
208 return False |
149 |
209 |
150 files = docsPath.glob("*.qch") |
210 files = docsPath.glob("*.qch") |
151 if not files: |
211 if not files: |
152 engine.setCustomValue(versionKey, '|') |
212 engine.setCustomValue(versionKey, "|") |
153 return False |
213 return False |
154 |
214 |
155 for f in files: |
215 for f in files: |
156 if f.stem == name: |
216 if f.stem == name: |
157 namespace = QHelpEngineCore.namespaceName(str(f.resolve())) |
217 namespace = QHelpEngineCore.namespaceName(str(f.resolve())) |
158 if not namespace: |
218 if not namespace: |
159 continue |
219 continue |
160 |
220 |
161 if ( |
221 if ( |
162 dt is not None and |
222 dt is not None |
163 namespace in engine.registeredDocumentations() and |
223 and namespace in engine.registeredDocumentations() |
164 (datetime.datetime.fromtimestamp(f.stat().st_mtime) == |
224 and (datetime.datetime.fromtimestamp(f.stat().st_mtime) == dt) |
165 dt) and |
225 and qchFile == str(f.resolve()) |
166 qchFile == str(f.resolve()) |
|
167 ): |
226 ): |
168 return False |
227 return False |
169 |
228 |
170 if namespace in engine.registeredDocumentations(): |
229 if namespace in engine.registeredDocumentations(): |
171 engine.unregisterDocumentation(namespace) |
230 engine.unregisterDocumentation(namespace) |
172 |
231 |
173 if not engine.registerDocumentation(str(f.resolve())): |
232 if not engine.registerDocumentation(str(f.resolve())): |
174 self.errorMessage.emit( |
233 self.errorMessage.emit( |
175 self.tr( |
234 self.tr( |
176 """<p>The file <b>{0}</b> could not be""" |
235 """<p>The file <b>{0}</b> could not be""" |
177 """ registered. <br/>Reason: {1}</p>""") |
236 """ registered. <br/>Reason: {1}</p>""" |
178 .format(f, engine.error()) |
237 ).format(f, engine.error()) |
179 ) |
238 ) |
180 return False |
239 return False |
181 |
240 |
182 engine.setCustomValue( |
241 engine.setCustomValue( |
183 versionKey, |
242 versionKey, |
184 datetime.datetime.fromtimestamp(f.stat().st_mtime) |
243 datetime.datetime.fromtimestamp(f.stat().st_mtime).isoformat() |
185 .isoformat() + '|' + str(f.resolve())) |
244 + "|" |
|
245 + str(f.resolve()), |
|
246 ) |
186 return True |
247 return True |
187 |
248 |
188 return False |
249 return False |
189 |
250 |
190 def __installEric7Doc(self, engine): |
251 def __installEric7Doc(self, engine): |
191 """ |
252 """ |
192 Private method to install/update the eric help documentation. |
253 Private method to install/update the eric help documentation. |
193 |
254 |
194 @param engine reference to the help engine |
255 @param engine reference to the help engine |
195 @type QHelpEngineCore |
256 @type QHelpEngineCore |
196 @return flag indicating success |
257 @return flag indicating success |
197 @rtype bool |
258 @rtype bool |
198 """ |
259 """ |
199 versionKey = "eric7_ide" |
260 versionKey = "eric7_ide" |
200 info = engine.customValue(versionKey, "") |
261 info = engine.customValue(versionKey, "") |
201 lst = info.split('|') |
262 lst = info.split("|") |
202 |
263 |
203 dt = None |
264 dt = None |
204 if len(lst) and lst[0]: |
265 if len(lst) and lst[0]: |
205 dt = datetime.datetime.fromisoformat(lst[0]) |
266 dt = datetime.datetime.fromisoformat(lst[0]) |
206 |
267 |
207 qchFile = "" |
268 qchFile = "" |
208 if len(lst) == 2: |
269 if len(lst) == 2: |
209 qchFile = lst[1] |
270 qchFile = lst[1] |
210 |
271 |
211 docsPath = pathlib.Path(getConfig("ericDocDir")) / "Help" |
272 docsPath = pathlib.Path(getConfig("ericDocDir")) / "Help" |
212 |
273 |
213 files = docsPath.glob("*.qch") |
274 files = docsPath.glob("*.qch") |
214 if not files: |
275 if not files: |
215 engine.setCustomValue(versionKey, '|') |
276 engine.setCustomValue(versionKey, "|") |
216 return False |
277 return False |
217 |
278 |
218 for f in files: |
279 for f in files: |
219 if f.name == "source.qch": |
280 if f.name == "source.qch": |
220 namespace = QHelpEngineCore.namespaceName(str(f.resolve())) |
281 namespace = QHelpEngineCore.namespaceName(str(f.resolve())) |
221 if not namespace: |
282 if not namespace: |
222 continue |
283 continue |
223 |
284 |
224 if ( |
285 if ( |
225 dt is not None and |
286 dt is not None |
226 namespace in engine.registeredDocumentations() and |
287 and namespace in engine.registeredDocumentations() |
227 (datetime.datetime.fromtimestamp(f.stat().st_mtime) == |
288 and (datetime.datetime.fromtimestamp(f.stat().st_mtime) == dt) |
228 dt) and |
289 and qchFile == str(f.resolve()) |
229 qchFile == str(f.resolve()) |
|
230 ): |
290 ): |
231 return False |
291 return False |
232 |
292 |
233 if namespace in engine.registeredDocumentations(): |
293 if namespace in engine.registeredDocumentations(): |
234 engine.unregisterDocumentation(namespace) |
294 engine.unregisterDocumentation(namespace) |
235 |
295 |
236 if not engine.registerDocumentation(str(f.resolve())): |
296 if not engine.registerDocumentation(str(f.resolve())): |
237 self.errorMessage.emit( |
297 self.errorMessage.emit( |
238 self.tr( |
298 self.tr( |
239 """<p>The file <b>{0}</b> could not be""" |
299 """<p>The file <b>{0}</b> could not be""" |
240 """ registered. <br/>Reason: {1}</p>""") |
300 """ registered. <br/>Reason: {1}</p>""" |
241 .format(f, engine.error()) |
301 ).format(f, engine.error()) |
242 ) |
302 ) |
243 return False |
303 return False |
244 |
304 |
245 engine.setCustomValue( |
305 engine.setCustomValue( |
246 versionKey, |
306 versionKey, |
247 datetime.datetime.fromtimestamp(f.stat().st_mtime) |
307 datetime.datetime.fromtimestamp(f.stat().st_mtime).isoformat() |
248 .isoformat() + '|' + str(f.resolve())) |
308 + "|" |
|
309 + str(f.resolve()), |
|
310 ) |
249 return True |
311 return True |
250 |
312 |
251 return False |
313 return False |