src/eric7/WebBrowser/GreaseMonkey/GreaseMonkeyManager.py

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

eric ide

mercurial