Helpviewer/GreaseMonkey/GreaseMonkeyManager.py

changeset 1953
26aa6fd94dc2
child 1954
5072605ad4dd
equal deleted inserted replaced
1952:af4103f0e93f 1953:26aa6fd94dc2
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2012 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the manager for GreaseMonkey scripts.
8 """
9
10 import os
11
12 from PyQt4.QtCore import pyqtSignal, QObject, QTimer, QFile, QDir, QSettings, QUrl, \
13 QByteArray
14 from PyQt4.QtNetwork import QNetworkAccessManager
15
16 from .GreaseMonkeyJavaScript import bootstrap_js
17 from .GreaseMonkeyDownloader import GreaseMonkeyDownloader
18 from .GreaseMonkeyScript import GreaseMonkeyScript
19
20 from .GreaseMonkeyConfiguration.GreaseMonkeyConfigurationDialog import \
21 GreaseMonkeyConfigurationDialog
22
23 from Helpviewer.Network.EmptyNetworkReply import EmptyNetworkReply
24
25 import Utilities
26 import Preferences
27
28
29 class GreaseMonkeyManager(QObject):
30 """
31 Class implementing the manager for GreaseMonkey scripts.
32 """
33 scriptsChanged = pyqtSignal()
34
35 def __init__(self, parent=None):
36 """
37 Constructor
38
39 @param parent reference to the parent object (QObject)
40 """
41 super().__init__(parent)
42
43 self.__disabledScripts = []
44 self.__endScripts = []
45 self.__startScripts = []
46 self.__downloaders = []
47
48 QTimer.singleShot(0, self.__load)
49
50 def showConfigurationDialog(self, parent=None):
51 """
52 Public method to show the configuration dialog.
53
54 @param parent reference to the parent widget (QWidget)
55 """
56 self.__configDiaolg = GreaseMonkeyConfigurationDialog(self, parent)
57 self.__configDiaolg.show()
58
59 def downloadScript(self, request):
60 """
61 Public method to download a GreaseMonkey script.
62
63 @param request reference to the request (QNetworkRequest)
64 """
65 downloader = GreaseMonkeyDownloader(request, self)
66 downloader.finished.connect(self.__downloaderFinished)
67 self.__downloaders.append(downloader)
68
69 def __downloaderFinished(self):
70 """
71 Private slot to handle the completion of a script download.
72 """
73 downloader = self.sender()
74 if downloader is None or downloader not in self.__downloaders:
75 return
76
77 self.__downloaders.remove(downloader)
78
79 def scriptsDirectory(self):
80 """
81 Public method to get the path of the scripts directory.
82
83 @return path of the scripts directory (string)
84 """
85 return os.path.join(Utilities.getConfigDir(), "browser", "greasemonkey")
86
87 def requireScriptsDirectory(self):
88 """
89 Public method to get the path of the scripts directory.
90
91 @return path of the scripts directory (string)
92 """
93 return os.path.join(self.scriptsDirectory(), "requires")
94
95 def requireScripts(self, urlList):
96 """
97 Public method to get the sources of all required scripts.
98
99 @param urlList list of URLs (list of string)
100 @return sources of all required scripts (string)
101 """
102 requiresDir = QDir(self.requireScriptsDirectory())
103 if not requiresDir.exists() or len(urlList) == 0:
104 return ""
105
106 script = ""
107
108 settings = QSettings(os.path.join(self.requireScriptsDirectory(), "requires.ini"),
109 QSettings.IniFormat)
110 settings.beginGroup("Files")
111 for url in urlList:
112 if settings.contains(url):
113 fileName = settings.value(url)
114 try:
115 f = open(fileName, "r")
116 source = f.read()
117 f.close()
118 except (IOError, OSError):
119 source = ""
120 script += source.strip() + "\n"
121
122 return script
123
124 def saveConfiguration(self):
125 """
126 Public method to save the configuration.
127 """
128 Preferences.setHelp("GreaseMonkeyDisabledScripts", self.__disabledScripts)
129
130 def allScripts(self):
131 """
132 Public method to get a list of all scripts.
133
134 @return list of all scripts (list of GreaseMonkeyScript)
135 """
136 return self.__startScripts[:] + self.__endScripts[:]
137
138 def containsScript(self, fullName):
139 """
140 Public method to check, if the given script exists.
141
142 @param fullName full name of the script (string)
143 @return flag indicating the existence (boolean)
144 """
145 for script in self.__startScripts:
146 if script.fullName() == fullName:
147 return True
148 for script in self.__endScripts:
149 if script.fullName() == fullName:
150 return True
151 return False
152
153 def enableScript(self, script):
154 """
155 Public method to enable the given script.
156
157 @param script script to be enabled (GreaseMonkeyScript)
158 """
159 script.setEnabled(True)
160 fullName = script.fullName()
161 if fullName in self.__disabledScripts:
162 self.__disabledScripts.remove(fullName)
163
164 def disableScript(self, script):
165 """
166 Public method to disable the given script.
167
168 @param script script to be disabled (GreaseMonkeyScript)
169 """
170 script.setEnabled(False)
171 fullName = script.fullName()
172 if fullName not in self.__disabledScripts:
173 self.__disabledScripts.append(fullName)
174
175 def addScript(self, script):
176 """
177 Public method to add a script.
178
179 @param script script to be added (GreaseMonkeyScript)
180 @return flag indicating success (boolean)
181 """
182 if not script:
183 return False
184
185 if script.startAt() == GreaseMonkeyScript.DocumentStart:
186 self.__startScripts.append(script)
187 else:
188 self.__endScripts.append(script)
189
190 self.scriptsChanged.emit()
191 return True
192
193 def removeScript(self, script):
194 """
195 Public method to remove a script.
196
197 @param script script to be removed (GreaseMonkeyScript)
198 @return flag indicating success (boolean)
199 """
200 if not script:
201 return False
202
203 if script.startAt() == GreaseMonkeyScript.DocumentStart:
204 try:
205 self.__startScripts.remove(script)
206 except ValueError:
207 pass
208 else:
209 try:
210 self.__endScripts.remove(script)
211 except ValueError:
212 pass
213
214 fullName = script.fullName()
215 if fullName in self.__disabledScripts:
216 self.__disabledScripts.remove(fullName)
217 QFile.remove(script.fileName())
218
219 self.scriptsChanged.emit()
220 return True
221
222 def canRunOnScheme(self, scheme):
223 """
224 Public method to check, if scripts can be run on a scheme.
225
226 @param scheme scheme to check (string)
227 @return flag indicating, that scripts can be run (boolean)
228 """
229 return scheme in ["http", "https", "data", "ftp"]
230
231 def pageLoadStarted(self):
232 """
233 Public slot to handle the start of loading a page.
234 """
235 frame = self.sender()
236 if not frame:
237 return
238
239 urlScheme = frame.url().scheme()
240 urlString = bytes(frame.url().toEncoded()).decode()
241
242 if not self.canRunOnScheme(urlScheme):
243 return
244
245 for script in self.__startScripts:
246 if script.match(urlString):
247 frame.evaluateJavaScript(bootstrap_js + script.script())
248
249 for script in self.__endScripts:
250 if script.match(urlString):
251 javascript = 'window.addEventListener("DOMContentLoaded",' \
252 'function(e) {{ {0} }}, false);'.format(
253 bootstrap_js + script.script())
254 frame.evaluateJavaScript(javascript)
255
256 def __load(self):
257 """
258 Private slot to load the available scripts into the manager.
259 """
260 scriptsDir = QDir(self.scriptsDirectory())
261 if not scriptsDir.exists():
262 scriptsDir.mkpath(self.scriptsDirectory())
263
264 if not scriptsDir.exists("requires"):
265 scriptsDir.mkdir("requires")
266
267 self.__disabledScripts = Preferences.getHelp("GreaseMonkeyDisabledScripts")
268
269 for fileName in scriptsDir.entryList(["*.js"], QDir.Files):
270 absolutePath = scriptsDir.absoluteFilePath(fileName)
271 script = GreaseMonkeyScript(self, absolutePath)
272
273 if script.fullName() in self.__disabledScripts:
274 script.setEnabled(False)
275
276 if script.startAt() == GreaseMonkeyScript.DocumentStart:
277 self.__startScripts.append(script)
278 else:
279 self.__endScripts.append(script)
280
281 def connectPage(self, page):
282 """
283 Public method to allow the GreaseMonkey manager to connect to the page.
284
285 @param page reference to the web page (HelpWebPage)
286 """
287 page.mainFrame().javaScriptWindowObjectCleared.connect(self.pageLoadStarted)
288
289 def createRequest(self, op, request, outgoingData=None):
290 """
291 Public method to create a request.
292
293 @param op the operation to be performed (QNetworkAccessManager.Operation)
294 @param request reference to the request object (QNetworkRequest)
295 @param outgoingData reference to an IODevice containing data to be sent
296 (QIODevice)
297 @return reference to the created reply object (QNetworkReply)
298 """
299 if op == QNetworkAccessManager.GetOperation and \
300 request.rawHeader("X-Eric5-UserLoadAction") == QByteArray("1"):
301 urlString = request.url().toString(QUrl.RemoveFragment | QUrl.RemoveQuery)
302 if urlString.endswith(".user.js"):
303 self.downloadScript(request)
304 return EmptyNetworkReply(self)
305
306 return None

eric ide

mercurial