eric7/QScintilla/APIsManager.py

branch
eric7
changeset 8312
800c432b34c8
parent 8218
7c09585bd960
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the APIsManager.
8 """
9
10 import os
11
12 from PyQt5.QtCore import QDir, QFileInfo, pyqtSignal, QObject
13 from PyQt5.Qsci import QsciAPIs
14
15 from . import Lexers
16 import Preferences
17 import Globals
18
19
20 class APIs(QObject):
21 """
22 Class implementing an API storage entity.
23
24 @signal apiPreparationFinished() emitted after the API preparation has
25 finished
26 @signal apiPreparationCancelled() emitted after the API preparation has
27 been cancelled
28 @signal apiPreparationStarted() emitted after the API preparation has
29 started
30 """
31 apiPreparationFinished = pyqtSignal()
32 apiPreparationCancelled = pyqtSignal()
33 apiPreparationStarted = pyqtSignal()
34
35 def __init__(self, language, projectType="", forPreparation=False,
36 parent=None):
37 """
38 Constructor
39
40 @param language language of the APIs object
41 @type str
42 @param projectType type of the project
43 @type str
44 @param forPreparation flag indicating this object is just needed
45 for a preparation process
46 @type bool
47 @param parent reference to the parent object
48 @type QObject
49 """
50 super().__init__(parent)
51 if projectType:
52 self.setObjectName("APIs_{0}_{1}".format(language, projectType))
53 else:
54 self.setObjectName("APIs_{0}".format(language))
55
56 self.__inPreparation = False
57 self.__language = language
58 self.__projectType = projectType
59 self.__forPreparation = forPreparation
60 self.__lexer = Lexers.getLexer(self.__language)
61 self.__apifiles = Preferences.getEditorAPI(self.__language,
62 self.__projectType)
63 self.__apifiles.sort()
64 if self.__lexer is None:
65 self.__apis = None
66 else:
67 self.__apis = QsciAPIs(self.__lexer)
68 self.__apis.apiPreparationFinished.connect(
69 self.__apiPreparationFinished)
70 self.__apis.apiPreparationCancelled.connect(
71 self.__apiPreparationCancelled)
72 self.__apis.apiPreparationStarted.connect(
73 self.__apiPreparationStarted)
74 self.__loadAPIs()
75
76 def __loadAPIs(self):
77 """
78 Private method to load the APIs.
79 """
80 if self.__apis.isPrepared():
81 # load a prepared API file
82 if (
83 not self.__forPreparation and
84 Preferences.getEditor("AutoPrepareAPIs")
85 ):
86 self.prepareAPIs()
87 self.__apis.loadPrepared(self.__preparedName())
88 else:
89 # load the raw files and prepare the API file
90 if (
91 not self.__forPreparation and
92 Preferences.getEditor("AutoPrepareAPIs")
93 ):
94 self.prepareAPIs(ondemand=True)
95
96 def reloadAPIs(self):
97 """
98 Public method to reload the API information.
99 """
100 if (
101 not self.__forPreparation and
102 Preferences.getEditor("AutoPrepareAPIs")
103 ):
104 self.prepareAPIs()
105 self.__loadAPIs()
106
107 def getQsciAPIs(self):
108 """
109 Public method to get a reference to QsciAPIs object.
110
111 @return reference to the QsciAPIs object (QsciAPIs)
112 """
113 if (
114 not self.__forPreparation and
115 Preferences.getEditor("AutoPrepareAPIs")
116 ):
117 self.prepareAPIs()
118 return self.__apis
119
120 def isEmpty(self):
121 """
122 Public method to check, if the object has API files configured.
123
124 @return flag indicating no API files have been configured (boolean)
125 """
126 return len(self.__apifiles) == 0
127
128 def __apiPreparationFinished(self):
129 """
130 Private method called to save an API, after it has been prepared.
131 """
132 self.__apis.savePrepared(self.__preparedName())
133 self.__inPreparation = False
134 self.apiPreparationFinished.emit()
135
136 def __apiPreparationCancelled(self):
137 """
138 Private method called, after the API preparation process has been
139 cancelled.
140 """
141 self.__inPreparation = False
142 self.apiPreparationCancelled.emit()
143
144 def __apiPreparationStarted(self):
145 """
146 Private method called, when the API preparation process started.
147 """
148 self.__inPreparation = True
149 self.apiPreparationStarted.emit()
150
151 def prepareAPIs(self, ondemand=False, rawList=None):
152 """
153 Public method to prepare the APIs if necessary.
154
155 @param ondemand flag indicating a requested preparation (boolean)
156 @param rawList list of raw API files (list of strings)
157 """
158 if self.__apis is None or self.__inPreparation:
159 return
160
161 needsPreparation = False
162 if ondemand:
163 needsPreparation = True
164 else:
165 # check, if a new preparation is necessary
166 preparedAPIs = self.__preparedName()
167 if preparedAPIs:
168 preparedAPIsInfo = QFileInfo(preparedAPIs)
169 if not preparedAPIsInfo.exists():
170 needsPreparation = True
171 else:
172 preparedAPIsTime = preparedAPIsInfo.lastModified()
173 apifiles = sorted(Preferences.getEditorAPI(
174 self.__language, self.__projectType))
175 if self.__apifiles != apifiles:
176 needsPreparation = True
177 for apifile in apifiles:
178 if (
179 QFileInfo(apifile).lastModified() >
180 preparedAPIsTime
181 ):
182 needsPreparation = True
183 break
184
185 if needsPreparation:
186 # do the preparation
187 self.__apis.clear()
188 if rawList:
189 apifiles = rawList
190 else:
191 apifiles = Preferences.getEditorAPI(
192 self.__language, self.__projectType)
193 for apifile in apifiles:
194 self.__apis.load(apifile)
195 self.__apis.prepare()
196 self.__apifiles = apifiles
197
198 def cancelPreparation(self):
199 """
200 Public slot to cancel the APIs preparation.
201 """
202 self.__apis and self.__apis.cancelPreparation()
203
204 def installedAPIFiles(self):
205 """
206 Public method to get a list of installed API files.
207
208 @return list of installed API files (list of strings)
209 """
210 if self.__apis is not None:
211 if Globals.isWindowsPlatform():
212 qsciPath = os.path.join(
213 Globals.getPyQt5ModulesDirectory(), "qsci")
214 if os.path.exists(qsciPath):
215 # it's the installer
216 if self.__lexer.lexerName() is not None:
217 apidir = os.path.join(qsciPath, "api",
218 self.__lexer.lexerName())
219 fnames = []
220 filist = QDir(apidir).entryInfoList(
221 ["*.api"], QDir.Filter.Files,
222 QDir.SortFlag.IgnoreCase)
223 for fi in filist:
224 fnames.append(fi.absoluteFilePath())
225 return fnames
226 else:
227 return []
228
229 return self.__apis.installedAPIFiles()
230 else:
231 return []
232
233 def __preparedName(self):
234 """
235 Private method returning the default name of a prepared API file.
236
237 @return complete filename for the Prepared APIs file (string)
238 """
239 apisDir = os.path.join(Globals.getConfigDir(), "APIs")
240 if self.__apis is not None:
241 if self.__projectType:
242 filename = "{0}_{1}.pap".format(self.__language,
243 self.__projectType)
244 else:
245 filename = "{0}.pap".format(self.__language)
246 return os.path.join(apisDir, filename)
247 else:
248 return ""
249
250
251 class APIsManager(QObject):
252 """
253 Class implementing the APIsManager class, which is the central store for
254 API information used by autocompletion and calltips.
255 """
256 def __init__(self, parent=None):
257 """
258 Constructor
259
260 @param parent reference to the parent object (QObject)
261 """
262 super().__init__(parent)
263 self.setObjectName("APIsManager")
264
265 self.__apis = {}
266
267 def reloadAPIs(self):
268 """
269 Public slot to reload the api information.
270 """
271 for api in list(self.__apis.values()):
272 api and api.reloadAPIs()
273
274 def getAPIs(self, language, projectType="", forPreparation=False):
275 """
276 Public method to get an APIs object for autocompletion/calltips.
277
278 This method creates and loads an APIs object dynamically upon request.
279 This saves memory for languages, that might not be needed at the
280 moment.
281
282 @param language language of the requested APIs object
283 @type str
284 @param projectType type of the project
285 @type str
286 @param forPreparation flag indicating the requested APIs object is just
287 needed for a preparation process
288 @type bool
289 @return reference to the APIs object
290 @rtype APIs
291 """
292 if forPreparation:
293 return APIs(language, projectType=projectType,
294 forPreparation=forPreparation)
295 else:
296 try:
297 return self.__apis[(language, projectType)]
298 except KeyError:
299 if language in Lexers.getSupportedApiLanguages():
300 # create the api object
301 self.__apis[(language, projectType)] = APIs(
302 language, projectType=projectType)
303 return self.__apis[(language, projectType)]
304 else:
305 return None

eric ide

mercurial