|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the manager for GreaseMonkey scripts. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 import os |
|
13 |
|
14 from PyQt5.QtCore import pyqtSignal, QObject, QTimer, QFile, QDir, QSettings, \ |
|
15 QUrl, QByteArray |
|
16 from PyQt5.QtNetwork import QNetworkAccessManager |
|
17 |
|
18 import Utilities |
|
19 import Preferences |
|
20 |
|
21 |
|
22 class GreaseMonkeyManager(QObject): |
|
23 """ |
|
24 Class implementing the manager for GreaseMonkey scripts. |
|
25 """ |
|
26 scriptsChanged = pyqtSignal() |
|
27 |
|
28 def __init__(self, parent=None): |
|
29 """ |
|
30 Constructor |
|
31 |
|
32 @param parent reference to the parent object (QObject) |
|
33 """ |
|
34 super(GreaseMonkeyManager, self).__init__(parent) |
|
35 |
|
36 self.__disabledScripts = [] |
|
37 self.__endScripts = [] |
|
38 self.__startScripts = [] |
|
39 self.__downloaders = [] |
|
40 |
|
41 QTimer.singleShot(0, self.__load) |
|
42 ## , m_interceptor(new GM_UrlInterceptor(this)) |
|
43 ##{ |
|
44 ## mApp->networkManager()->installUrlInterceptor(m_interceptor); |
|
45 ## |
|
46 ## QTimer::singleShot(0, this, SLOT(load())); |
|
47 ##} |
|
48 ## |
|
49 ##GM_Manager::~GM_Manager() |
|
50 ##{ |
|
51 ## mApp->networkManager()->removeUrlInterceptor(m_interceptor); |
|
52 ##} |
|
53 |
|
54 def showConfigurationDialog(self, parent=None): |
|
55 """ |
|
56 Public method to show the configuration dialog. |
|
57 |
|
58 @param parent reference to the parent widget (QWidget) |
|
59 """ |
|
60 from .GreaseMonkeyConfiguration.GreaseMonkeyConfigurationDialog \ |
|
61 import GreaseMonkeyConfigurationDialog |
|
62 self.__configDiaolg = GreaseMonkeyConfigurationDialog(self, parent) |
|
63 self.__configDiaolg.show() |
|
64 |
|
65 def downloadScript(self, request): |
|
66 """ |
|
67 Public method to download a GreaseMonkey script. |
|
68 |
|
69 @param request reference to the request (QNetworkRequest) |
|
70 """ |
|
71 from .GreaseMonkeyDownloader import GreaseMonkeyDownloader |
|
72 downloader = GreaseMonkeyDownloader(request, self) |
|
73 downloader.finished.connect(self.__downloaderFinished) |
|
74 self.__downloaders.append(downloader) |
|
75 |
|
76 def __downloaderFinished(self): |
|
77 """ |
|
78 Private slot to handle the completion of a script download. |
|
79 """ |
|
80 downloader = self.sender() |
|
81 if downloader is None or downloader not in self.__downloaders: |
|
82 return |
|
83 |
|
84 self.__downloaders.remove(downloader) |
|
85 |
|
86 def scriptsDirectory(self): |
|
87 """ |
|
88 Public method to get the path of the scripts directory. |
|
89 |
|
90 @return path of the scripts directory (string) |
|
91 """ |
|
92 return os.path.join( |
|
93 Utilities.getConfigDir(), "web_browser", "greasemonkey") |
|
94 |
|
95 def requireScriptsDirectory(self): |
|
96 """ |
|
97 Public method to get the path of the scripts directory. |
|
98 |
|
99 @return path of the scripts directory (string) |
|
100 """ |
|
101 return os.path.join(self.scriptsDirectory(), "requires") |
|
102 |
|
103 def requireScripts(self, urlList): |
|
104 """ |
|
105 Public method to get the sources of all required scripts. |
|
106 |
|
107 @param urlList list of URLs (list of string) |
|
108 @return sources of all required scripts (string) |
|
109 """ |
|
110 requiresDir = QDir(self.requireScriptsDirectory()) |
|
111 if not requiresDir.exists() or len(urlList) == 0: |
|
112 return "" |
|
113 |
|
114 script = "" |
|
115 |
|
116 settings = QSettings( |
|
117 os.path.join(self.requireScriptsDirectory(), "requires.ini"), |
|
118 QSettings.IniFormat) |
|
119 settings.beginGroup("Files") |
|
120 for url in urlList: |
|
121 if settings.contains(url): |
|
122 fileName = settings.value(url) |
|
123 try: |
|
124 f = open(fileName, "r", encoding="utf-8") |
|
125 source = f.read() |
|
126 f.close() |
|
127 except (IOError, OSError): |
|
128 source = "" |
|
129 script += source.strip() + "\n" |
|
130 |
|
131 return script |
|
132 |
|
133 def saveConfiguration(self): |
|
134 """ |
|
135 Public method to save the configuration. |
|
136 """ |
|
137 Preferences.setWebBrowser("GreaseMonkeyDisabledScripts", |
|
138 self.__disabledScripts) |
|
139 |
|
140 def allScripts(self): |
|
141 """ |
|
142 Public method to get a list of all scripts. |
|
143 |
|
144 @return list of all scripts (list of GreaseMonkeyScript) |
|
145 """ |
|
146 return self.__startScripts[:] + self.__endScripts[:] |
|
147 |
|
148 def containsScript(self, fullName): |
|
149 """ |
|
150 Public method to check, if the given script exists. |
|
151 |
|
152 @param fullName full name of the script (string) |
|
153 @return flag indicating the existence (boolean) |
|
154 """ |
|
155 for script in self.__startScripts: |
|
156 if script.fullName() == fullName: |
|
157 return True |
|
158 for script in self.__endScripts: |
|
159 if script.fullName() == fullName: |
|
160 return True |
|
161 return False |
|
162 |
|
163 def enableScript(self, script): |
|
164 """ |
|
165 Public method to enable the given script. |
|
166 |
|
167 @param script script to be enabled (GreaseMonkeyScript) |
|
168 """ |
|
169 script.setEnabled(True) |
|
170 fullName = script.fullName() |
|
171 if fullName in self.__disabledScripts: |
|
172 self.__disabledScripts.remove(fullName) |
|
173 ##void GM_Manager::enableScript(GM_Script* script) |
|
174 ##{ |
|
175 ## script->setEnabled(true); |
|
176 ## m_disabledScripts.removeOne(script->fullName()); |
|
177 ## |
|
178 ## QWebEngineScriptCollection *collection = mApp->webProfile()->scripts(); |
|
179 ## collection->insert(script->webScript()); |
|
180 ##} |
|
181 |
|
182 def disableScript(self, script): |
|
183 """ |
|
184 Public method to disable the given script. |
|
185 |
|
186 @param script script to be disabled (GreaseMonkeyScript) |
|
187 """ |
|
188 script.setEnabled(False) |
|
189 fullName = script.fullName() |
|
190 if fullName not in self.__disabledScripts: |
|
191 self.__disabledScripts.append(fullName) |
|
192 ##void GM_Manager::disableScript(GM_Script* script) |
|
193 ##{ |
|
194 ## script->setEnabled(false); |
|
195 ## m_disabledScripts.append(script->fullName()); |
|
196 ## |
|
197 ## QWebEngineScriptCollection *collection = mApp->webProfile()->scripts(); |
|
198 ## collection->remove(collection->findScript(script->fullName())); |
|
199 |
|
200 def addScript(self, script): |
|
201 """ |
|
202 Public method to add a script. |
|
203 |
|
204 @param script script to be added (GreaseMonkeyScript) |
|
205 @return flag indicating success (boolean) |
|
206 """ |
|
207 if not script: |
|
208 return False |
|
209 |
|
210 from .GreaseMonkeyScript import GreaseMonkeyScript |
|
211 if script.startAt() == GreaseMonkeyScript.DocumentStart: |
|
212 self.__startScripts.append(script) |
|
213 else: |
|
214 self.__endScripts.append(script) |
|
215 |
|
216 self.scriptsChanged.emit() |
|
217 return True |
|
218 ##bool GM_Manager::addScript(GM_Script* script) |
|
219 ##{ |
|
220 ## if (!script || !script->isValid()) { |
|
221 ## return false; |
|
222 ## } |
|
223 ## |
|
224 ## m_scripts.append(script); |
|
225 ## connect(script, &GM_Script::scriptChanged, this, &GM_Manager::scriptChanged); |
|
226 ## |
|
227 ## QWebEngineScriptCollection *collection = mApp->webProfile()->scripts(); |
|
228 ## collection->insert(script->webScript()); |
|
229 ## |
|
230 ## emit scriptsChanged(); |
|
231 ## return true; |
|
232 ##} |
|
233 |
|
234 def removeScript(self, script): |
|
235 """ |
|
236 Public method to remove a script. |
|
237 |
|
238 @param script script to be removed (GreaseMonkeyScript) |
|
239 @return flag indicating success (boolean) |
|
240 """ |
|
241 if not script: |
|
242 return False |
|
243 |
|
244 from .GreaseMonkeyScript import GreaseMonkeyScript |
|
245 if script.startAt() == GreaseMonkeyScript.DocumentStart: |
|
246 try: |
|
247 self.__startScripts.remove(script) |
|
248 except ValueError: |
|
249 pass |
|
250 else: |
|
251 try: |
|
252 self.__endScripts.remove(script) |
|
253 except ValueError: |
|
254 pass |
|
255 |
|
256 fullName = script.fullName() |
|
257 if fullName in self.__disabledScripts: |
|
258 self.__disabledScripts.remove(fullName) |
|
259 QFile.remove(script.fileName()) |
|
260 |
|
261 self.scriptsChanged.emit() |
|
262 return True |
|
263 ##bool GM_Manager::removeScript(GM_Script* script, bool removeFile) |
|
264 ##{ |
|
265 ## if (!script) { |
|
266 ## return false; |
|
267 ## } |
|
268 ## |
|
269 ## m_scripts.removeOne(script); |
|
270 ## |
|
271 ## QWebEngineScriptCollection *collection = mApp->webProfile()->scripts(); |
|
272 ## collection->remove(collection->findScript(script->fullName())); |
|
273 ## |
|
274 ## m_disabledScripts.removeOne(script->fullName()); |
|
275 ## |
|
276 ## if (removeFile) { |
|
277 ## QFile::remove(script->fileName()); |
|
278 ## delete script; |
|
279 ## } |
|
280 ## |
|
281 ## emit scriptsChanged(); |
|
282 ## return true; |
|
283 ##} |
|
284 |
|
285 def canRunOnScheme(self, scheme): |
|
286 """ |
|
287 Public method to check, if scripts can be run on a scheme. |
|
288 |
|
289 @param scheme scheme to check (string) |
|
290 @return flag indicating, that scripts can be run (boolean) |
|
291 """ |
|
292 return scheme in ["http", "https", "data", "ftp"] |
|
293 |
|
294 ## def pageLoadStarted(self): |
|
295 ## """ |
|
296 ## Public slot to handle the start of loading a page. |
|
297 ## """ |
|
298 ## frame = self.sender() |
|
299 ## if not frame: |
|
300 ## return |
|
301 ## |
|
302 ## urlScheme = frame.url().scheme() |
|
303 ## urlString = bytes(frame.url().toEncoded()).decode() |
|
304 ## |
|
305 ## if not self.canRunOnScheme(urlScheme): |
|
306 ## return |
|
307 ## |
|
308 ## from .GreaseMonkeyJavaScript import bootstrap_js |
|
309 ## for script in self.__startScripts: |
|
310 ## if script.match(urlString): |
|
311 ## frame.evaluateJavaScript(bootstrap_js + script.script()) |
|
312 ## |
|
313 ## for script in self.__endScripts: |
|
314 ## if script.match(urlString): |
|
315 ## javascript = 'window.addEventListener("DOMContentLoaded",' \ |
|
316 ## 'function(e) {{ {0} }}, false);'.format( |
|
317 ## bootstrap_js + script.script()) |
|
318 ## frame.evaluateJavaScript(javascript) |
|
319 |
|
320 def __load(self): |
|
321 """ |
|
322 Private slot to load the available scripts into the manager. |
|
323 """ |
|
324 scriptsDir = QDir(self.scriptsDirectory()) |
|
325 if not scriptsDir.exists(): |
|
326 scriptsDir.mkpath(self.scriptsDirectory()) |
|
327 |
|
328 if not scriptsDir.exists("requires"): |
|
329 scriptsDir.mkdir("requires") |
|
330 |
|
331 self.__disabledScripts = \ |
|
332 Preferences.getHelp("GreaseMonkeyDisabledScripts") |
|
333 |
|
334 from .GreaseMonkeyScript import GreaseMonkeyScript |
|
335 for fileName in scriptsDir.entryList(["*.js"], QDir.Files): |
|
336 absolutePath = scriptsDir.absoluteFilePath(fileName) |
|
337 script = GreaseMonkeyScript(self, absolutePath) |
|
338 |
|
339 if script.fullName() in self.__disabledScripts: |
|
340 script.setEnabled(False) |
|
341 |
|
342 if script.startAt() == GreaseMonkeyScript.DocumentStart: |
|
343 self.__startScripts.append(script) |
|
344 else: |
|
345 self.__endScripts.append(script) |
|
346 ##void GM_Manager::load() |
|
347 ##{ |
|
348 ## QDir gmDir(m_settingsPath + QL1S("/greasemonkey")); |
|
349 ## if (!gmDir.exists()) { |
|
350 ## gmDir.mkdir(m_settingsPath + QL1S("/greasemonkey")); |
|
351 ## } |
|
352 ## |
|
353 ## if (!gmDir.exists("requires")) { |
|
354 ## gmDir.mkdir("requires"); |
|
355 ## } |
|
356 ## |
|
357 ## m_bootstrapScript = QzTools::readAllFileContents(":gm/data/bootstrap.min.js"); |
|
358 ## m_valuesScript = QzTools::readAllFileContents(":gm/data/values.min.js"); |
|
359 ## |
|
360 ## QSettings settings(m_settingsPath + QL1S("/extensions.ini"), QSettings::IniFormat); |
|
361 ## settings.beginGroup("GreaseMonkey"); |
|
362 ## m_disabledScripts = settings.value("disabledScripts", QStringList()).toStringList(); |
|
363 ## |
|
364 ## foreach (const QString &fileName, gmDir.entryList(QStringList("*.js"), QDir::Files)) { |
|
365 ## const QString absolutePath = gmDir.absoluteFilePath(fileName); |
|
366 ## GM_Script* script = new GM_Script(this, absolutePath); |
|
367 ## |
|
368 ## if (!script->isValid()) { |
|
369 ## delete script; |
|
370 ## continue; |
|
371 ## } |
|
372 ## |
|
373 ## m_scripts.append(script); |
|
374 ## |
|
375 ## if (m_disabledScripts.contains(script->fullName())) { |
|
376 ## script->setEnabled(false); |
|
377 ## } |
|
378 ## else { |
|
379 ## mApp->webProfile()->scripts()->insert(script->webScript()); |
|
380 ## } |
|
381 ## } |
|
382 ##} |
|
383 |
|
384 def __scriptChanged(self): |
|
385 """ |
|
386 Private slot handling a changed script. |
|
387 """ |
|
388 ##void GM_Manager::scriptChanged() |
|
389 ##{ |
|
390 ## GM_Script *script = qobject_cast<GM_Script*>(sender()); |
|
391 ## if (!script) |
|
392 ## return; |
|
393 ## |
|
394 ## QWebEngineScriptCollection *collection = mApp->webProfile()->scripts(); |
|
395 ## collection->remove(collection->findScript(script->fullName())); |
|
396 ## collection->insert(script->webScript()); |
|
397 ##} |
|
398 |
|
399 ## def connectPage(self, page): |
|
400 ## """ |
|
401 ## Public method to allow the GreaseMonkey manager to connect to the page. |
|
402 ## |
|
403 ## @param page reference to the web page (HelpWebPage) |
|
404 ## """ |
|
405 ## page.mainFrame().javaScriptWindowObjectCleared.connect( |
|
406 ## self.pageLoadStarted) |
|
407 ## |
|
408 ## def createRequest(self, op, request, outgoingData=None): |
|
409 ## """ |
|
410 ## Public method to create a request. |
|
411 ## |
|
412 ## @param op the operation to be performed |
|
413 ## (QNetworkAccessManager.Operation) |
|
414 ## @param request reference to the request object (QNetworkRequest) |
|
415 ## @param outgoingData reference to an IODevice containing data to be sent |
|
416 ## (QIODevice) |
|
417 ## @return reference to the created reply object (QNetworkReply) |
|
418 ## """ |
|
419 ## if op == QNetworkAccessManager.GetOperation and \ |
|
420 ## request.rawHeader(b"X-Eric6-UserLoadAction") == QByteArray(b"1"): |
|
421 ## urlString = request.url().toString( |
|
422 ## QUrl.RemoveFragment | QUrl.RemoveQuery) |
|
423 ## if urlString.endswith(".user.js"): |
|
424 ## self.downloadScript(request) |
|
425 ## from Helpviewer.Network.EmptyNetworkReply import \ |
|
426 ## EmptyNetworkReply |
|
427 ## return EmptyNetworkReply(self) |
|
428 ## |
|
429 ## return None |