eric7/WebBrowser/GreaseMonkey/GreaseMonkeyManager.py

branch
eric7
changeset 8312
800c432b34c8
parent 8240
93b8a353c4bf
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2012 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the manager for GreaseMonkey scripts.
8 """
9
10 import os
11 import contextlib
12
13 from PyQt5.QtCore import (
14 pyqtSignal, pyqtSlot, Qt, QObject, QTimer, QFile, QFileInfo, QDir,
15 QSettings, QMetaObject, QUrl, Q_ARG, QCoreApplication
16 )
17 from PyQt5.QtWidgets import QDialog
18
19 from E5Gui import E5MessageBox
20
21 import Utilities
22 import Preferences
23
24 from WebBrowser.WebBrowserWindow import WebBrowserWindow
25 from WebBrowser.JavaScript.ExternalJsObject import ExternalJsObject
26
27 from .GreaseMonkeyJsObject import GreaseMonkeyJsObject
28
29
30 class GreaseMonkeyManager(QObject):
31 """
32 Class implementing the manager for GreaseMonkey scripts.
33
34 @signal scriptsChanged() emitted to indicate a change of scripts
35 """
36 scriptsChanged = pyqtSignal()
37
38 def __init__(self, parent=None):
39 """
40 Constructor
41
42 @param parent reference to the parent object (QObject)
43 """
44 super().__init__(parent)
45
46 self.__disabledScripts = []
47 self.__scripts = []
48 self.__downloaders = []
49
50 self.__jsObject = GreaseMonkeyJsObject(self)
51
52 QTimer.singleShot(0, self.__load)
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 import GreaseMonkeyConfigurationDialog
61 self.__configDiaolg = (
62 GreaseMonkeyConfigurationDialog.GreaseMonkeyConfigurationDialog(
63 self, parent)
64 )
65 self.__configDiaolg.show()
66
67 def downloadScript(self, url):
68 """
69 Public method to download a GreaseMonkey script.
70
71 @param url URL to download script from
72 @type QUrl
73 """
74 QMetaObject.invokeMethod(
75 self, "doDownloadScript", Qt.ConnectionType.QueuedConnection,
76 Q_ARG(QUrl, url))
77
78 @pyqtSlot(QUrl)
79 def doDownloadScript(self, url):
80 """
81 Public slot to download a GreaseMonkey script.
82
83 Note: The download needed to be separated in the invoking part
84 (s.a.) and the one doing the real download because the invoking
85 part runs in a different thread (i.e. the web engine thread).
86
87 @param url URL to download script from
88 @type QUrl
89 """
90 from .GreaseMonkeyDownloader import GreaseMonkeyDownloader
91 downloader = GreaseMonkeyDownloader(
92 url, self, GreaseMonkeyDownloader.DownloadMainScript)
93 downloader.finished.connect(
94 lambda f: self.__downloaderFinished(f, downloader))
95 self.__downloaders.append(downloader)
96
97 def __downloaderFinished(self, fileName, downloader):
98 """
99 Private slot to handle the completion of a script download.
100
101 @param fileName name of the downloaded script
102 @type str
103 @param downloader reference to the downloader object
104 @type GreaseMonkeyDownloader
105 """
106 if downloader in self.__downloaders:
107 self.__downloaders.remove(downloader)
108
109 deleteScript = True
110 from .GreaseMonkeyScript import GreaseMonkeyScript
111 script = GreaseMonkeyScript(self, fileName)
112 if script.isValid():
113 if not self.containsScript(script.fullName()):
114 from .GreaseMonkeyAddScriptDialog import (
115 GreaseMonkeyAddScriptDialog
116 )
117 dlg = GreaseMonkeyAddScriptDialog(self, script)
118 deleteScript = dlg.exec() != QDialog.DialogCode.Accepted
119 else:
120 E5MessageBox.information(
121 None,
122 QCoreApplication.translate(
123 "GreaseMonkeyManager",
124 "Install GreaseMonkey Script"),
125 QCoreApplication.translate(
126 "GreaseMonkeyManager",
127 """'{0}' is already installed.""").format(
128 script.fullName())
129 )
130
131 if deleteScript:
132 with contextlib.suppress(OSError):
133 os.remove(fileName)
134
135 def scriptsDirectory(self):
136 """
137 Public method to get the path of the scripts directory.
138
139 @return path of the scripts directory (string)
140 """
141 return os.path.join(
142 Utilities.getConfigDir(), "web_browser", "greasemonkey")
143
144 def requireScriptsDirectory(self):
145 """
146 Public method to get the path of the scripts directory.
147
148 @return path of the scripts directory (string)
149 """
150 return os.path.join(self.scriptsDirectory(), "requires")
151
152 def requireScripts(self, urlList):
153 """
154 Public method to get the sources of all required scripts.
155
156 @param urlList list of URLs (list of string)
157 @return sources of all required scripts (string)
158 """
159 requiresDir = QDir(self.requireScriptsDirectory())
160 if not requiresDir.exists() or len(urlList) == 0:
161 return ""
162
163 script = ""
164
165 settings = QSettings(
166 os.path.join(self.requireScriptsDirectory(), "requires.ini"),
167 QSettings.Format.IniFormat)
168 settings.beginGroup("Files")
169 for url in urlList:
170 if settings.contains(url):
171 fileName = settings.value(url)
172 if not QFileInfo(fileName).isAbsolute():
173 fileName = os.path.join(self.requireScriptsDirectory(),
174 fileName)
175 try:
176 with open(fileName, "r", encoding="utf-8") as f:
177 source = f.read().strip()
178 except OSError:
179 source = ""
180 if source:
181 script += source + "\n"
182
183 return script
184
185 def saveConfiguration(self):
186 """
187 Public method to save the configuration.
188 """
189 Preferences.setWebBrowser("GreaseMonkeyDisabledScripts",
190 self.__disabledScripts)
191
192 def allScripts(self):
193 """
194 Public method to get a list of all scripts.
195
196 @return list of all scripts (list of GreaseMonkeyScript)
197 """
198 return self.__scripts[:]
199
200 def containsScript(self, fullName):
201 """
202 Public method to check, if the given script exists.
203
204 @param fullName full name of the script (string)
205 @return flag indicating the existence (boolean)
206 """
207 return any(script.fullName() == fullName for script in self.__scripts)
208
209 def enableScript(self, script):
210 """
211 Public method to enable the given script.
212
213 @param script script to be enabled (GreaseMonkeyScript)
214 """
215 script.setEnabled(True)
216 fullName = script.fullName()
217 if fullName in self.__disabledScripts:
218 self.__disabledScripts.remove(fullName)
219
220 collection = WebBrowserWindow.webProfile().scripts()
221 collection.insert(script.webScript())
222
223 def disableScript(self, script):
224 """
225 Public method to disable the given script.
226
227 @param script script to be disabled (GreaseMonkeyScript)
228 """
229 script.setEnabled(False)
230 fullName = script.fullName()
231 if fullName not in self.__disabledScripts:
232 self.__disabledScripts.append(fullName)
233
234 collection = WebBrowserWindow.webProfile().scripts()
235 collection.remove(collection.findScript(fullName))
236
237 def addScript(self, script):
238 """
239 Public method to add a script.
240
241 @param script script to be added (GreaseMonkeyScript)
242 @return flag indicating success (boolean)
243 """
244 if not script or not script.isValid():
245 return False
246
247 self.__scripts.append(script)
248 script.scriptChanged.connect(lambda: self.__scriptChanged(script))
249
250 collection = WebBrowserWindow.webProfile().scripts()
251 collection.insert(script.webScript())
252
253 self.scriptsChanged.emit()
254 return True
255
256 def removeScript(self, script, removeFile=True):
257 """
258 Public method to remove a script.
259
260 @param script script to be removed (GreaseMonkeyScript)
261 @param removeFile flag indicating to remove the script file as well
262 (bool)
263 @return flag indicating success (boolean)
264 """
265 if not script:
266 return False
267
268 with contextlib.suppress(ValueError):
269 self.__scripts.remove(script)
270
271 fullName = script.fullName()
272 collection = WebBrowserWindow.webProfile().scripts()
273 collection.remove(collection.findScript(fullName))
274
275 if fullName in self.__disabledScripts:
276 self.__disabledScripts.remove(fullName)
277
278 if removeFile:
279 QFile.remove(script.fileName())
280 del script
281
282 self.scriptsChanged.emit()
283 return True
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 __load(self):
295 """
296 Private slot to load the available scripts into the manager.
297 """
298 scriptsDir = QDir(self.scriptsDirectory())
299 if not scriptsDir.exists():
300 scriptsDir.mkpath(self.scriptsDirectory())
301
302 if not scriptsDir.exists("requires"):
303 scriptsDir.mkdir("requires")
304
305 self.__disabledScripts = Preferences.getWebBrowser(
306 "GreaseMonkeyDisabledScripts")
307
308 from .GreaseMonkeyScript import GreaseMonkeyScript
309 for fileName in scriptsDir.entryList(["*.js"], QDir.Filter.Files):
310 absolutePath = scriptsDir.absoluteFilePath(fileName)
311 script = GreaseMonkeyScript(self, absolutePath)
312
313 if not script.isValid():
314 del script
315 continue
316
317 self.__scripts.append(script)
318
319 if script.fullName() in self.__disabledScripts:
320 script.setEnabled(False)
321 else:
322 collection = WebBrowserWindow.webProfile().scripts()
323 collection.insert(script.webScript())
324
325 self.__jsObject.setSettingsFile(os.path.join(
326 Utilities.getConfigDir(), "web_browser",
327 "greasemonkey_values.ini"))
328 ExternalJsObject.registerExtraObject("GreaseMonkey", self.__jsObject)
329
330 def __scriptChanged(self, script):
331 """
332 Private slot handling a changed script.
333
334 @param script reference to the changed script
335 @type GreaseMonkeyScript
336 """
337 fullName = script.fullName()
338 collection = WebBrowserWindow.webProfile().scripts()
339 collection.remove(collection.findScript(fullName))
340 collection.insert(script.webScript())

eric ide

mercurial