src/eric7/WebBrowser/GreaseMonkey/GreaseMonkeyManager.py

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

eric ide

mercurial