AssistantEric/APIsManager.py

changeset 2
89cbc07f4bf0
child 4
eb4cc276920c
equal deleted inserted replaced
1:3a4123edc944 2:89cbc07f4bf0
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2008 - 2010 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the APIsManager.
8 """
9
10 import os
11
12 from PyQt4.QtCore import *
13 from PyQt4.QtSql import QSqlDatabase, QSqlQuery
14
15 from E5Gui.E5Application import e5App
16
17 import QScintilla.Lexers
18
19 from DocumentationTools.APIGenerator import APIGenerator
20 import Utilities.ModuleParser
21 import Utilities
22 import Preferences
23
24 WorkerStarted = QEvent.User + 2001
25 WorkerFinished = QEvent.User + 2002
26 WorkerAborted = QEvent.User + 2003
27
28 ApisNameProject = "__Project__"
29
30 class DbAPIsWorker(QThread):
31 """
32 Class implementing a worker thread to prepare the API database.
33 """
34 populate_api_stmt = """
35 INSERT INTO api (acWord, context, fullContext, signature, fileId, pictureId)
36 VALUES (:acWord, :context, :fullContext, :signature, :fileId, :pictureId)
37 """
38 populate_del_api_stmt = """
39 DELETE FROM api WHERE fileId = :fileId
40 """
41 populate_file_stmt = """
42 INSERT INTO file (file) VALUES (:file)
43 """
44 update_file_stmt = """
45 UPDATE file SET lastRead = :lastRead WHERE file = :file
46 """
47
48 file_loaded_stmt = """
49 SELECT lastRead from file WHERE file = :file
50 """
51 file_id_stmt = """
52 SELECT id FROM file WHERE file = :file
53 """
54 file_delete_id_stmt = """
55 DELETE FROM file WHERE id = :id
56 """
57
58 def __init__(self, proxy, language, apiFiles, projectPath = ""):
59 """
60 Constructor
61
62 @param proxy reference to the object that is proxied (DbAPIs)
63 @param language language of the APIs object (string)
64 @param apiFiles list of API files to process (list of strings)
65 @param projectPath path of the project. Only needed, if the APIs
66 are extracted out of the sources of a project. (string)
67 """
68 QThread.__init__(self)
69
70 self.setTerminationEnabled(True)
71
72 # Get the AC word separators for all of the languages that the editor supports.
73 # This has to be before we create a new thread, because access to GUI elements
74 # is not allowed from non-gui threads.
75 self.__wseps = {}
76 for lang in QScintilla.Lexers.getSupportedLanguages():
77 lexer = QScintilla.Lexers.getLexer(lang)
78 if lexer is not None:
79 self.__wseps[lang] = lexer.autoCompletionWordSeparators()
80
81 self.__proxy = proxy
82 self.__language = language
83 self.__apiFiles = apiFiles[:]
84 self.__aborted = False
85 self.__projectPath = projectPath
86
87 def __autoCompletionWordSeparators(self, language):
88 """
89 Private method to get the word separator characters for a language.
90
91 @param language language of the APIs object (string)
92 @return word separator characters (list of strings)
93 """
94 return self.__wseps.get(language, None)
95
96 def abort(self):
97 """
98 Public method to ask the thread to stop.
99 """
100 self.__aborted = True
101
102 def __loadApiFileIfNewer(self, apiFile):
103 """
104 Private method to load an API file, if it is newer than the one read
105 into the database.
106
107 @param apiFile filename of the raw API file (string)
108 """
109 db = QSqlDatabase.database(self.__language)
110 db.transaction()
111 try:
112 query = QSqlQuery(db)
113 query.prepare(self.file_loaded_stmt)
114 query.bindValue(":file", apiFile)
115 query.exec_()
116 if query.next() and query.isValid():
117 loadTime = QDateTime.fromString(query.value(0), Qt.ISODate)
118 else:
119 loadTime = QDateTime(1970, 1, 1, 0, 0)
120 del query
121 finally:
122 db.commit()
123 if self.__projectPath:
124 modTime = QFileInfo(os.path.join(self.__projectPath, apiFile)).lastModified()
125 else:
126 modTime = QFileInfo(apiFile).lastModified()
127 if loadTime < modTime:
128 self.__loadApiFile(apiFile)
129
130 def __loadApiFile(self, apiFile):
131 """
132 Private method to read a raw API file into the database.
133
134 @param apiFile filename of the raw API file (string)
135 """
136 if self.__language == ApisNameProject:
137 try:
138 module = Utilities.ModuleParser.readModule(
139 os.path.join(self.__projectPath, apiFile),
140 basename = self.__projectPath + os.sep,
141 caching = False)
142 language = module.getType()
143 if language:
144 apiGenerator = APIGenerator(module)
145 apis = apiGenerator.genAPI(True, "", True)
146 else:
147 apis = []
148 except (IOError, ImportError):
149 apis = []
150 else:
151 try:
152 apis = Utilities.readEncodedFile(apiFile)[0].splitlines(True)
153 except (IOError, UnicodeError):
154 apis = []
155 language = None
156
157 if len(apis) > 0:
158 self.__storeApis(apis, apiFile, language)
159
160 def __storeApis(self, apis, apiFile, language):
161 """
162 Private method to put the API entries into the database.
163
164 @param apis list of api entries (list of strings)
165 @param apiFile filename of the file read to get the APIs (string)
166 @param language programming language of the file of the APIs (string)
167 """
168 if language:
169 wseps = self.__autoCompletionWordSeparators(language)
170 else:
171 wseps = self.__proxy.autoCompletionWordSeparators()
172 if wseps is None:
173 return
174
175 db = QSqlDatabase.database(self.__language)
176 db.transaction()
177 try:
178 query = QSqlQuery(db)
179 # step 1: create entry in file table and get the ID
180 query.prepare(self.populate_file_stmt)
181 query.bindValue(":file", apiFile)
182 query.exec_()
183 query.prepare(self.file_id_stmt)
184 query.bindValue(":file", apiFile)
185 query.exec_()
186 query.next()
187 id = int(query.value(0))
188
189 # step 2: delete all entries belonging to this file
190 query.prepare(self.populate_del_api_stmt)
191 query.bindValue(":fileId", id)
192 query.exec_()
193
194 # step 3: load the given api file
195 query.prepare(self.populate_api_stmt)
196 for api in apis:
197 if self.__aborted:
198 break
199
200 api = api.strip()
201 if len(api) == 0:
202 continue
203
204 b = api.find('(')
205 if b == -1:
206 path = api
207 sig = ""
208 else:
209 path = api[:b]
210 sig = api[b:]
211
212 while len(path) > 0:
213 acWord = ""
214 context = ""
215 fullContext = ""
216 pictureId = ""
217
218 # search for word separators
219 index = len(path)
220 while index > 0:
221 index -= 1
222 found = False
223 for wsep in wseps:
224 if path[:index].endswith(wsep):
225 found = True
226 break
227 if found:
228 if acWord == "":
229 # completion found
230 acWord = path[index:]
231 path = path[:(index - len(wsep))]
232 index = len(path)
233 fullContext = path
234 context = path
235 try:
236 acWord, pictureId = acWord.split("?", 1)
237 except ValueError:
238 pass
239 else:
240 context = path[index:]
241 break
242 # none found?
243 if acWord == "":
244 acWord = path
245 path = ""
246
247 query.bindValue(":acWord", acWord)
248 query.bindValue(":context", context)
249 query.bindValue(":fullContext", fullContext)
250 query.bindValue(":signature", sig)
251 query.bindValue(":fileId", id)
252 query.bindValue(":pictureId", pictureId)
253 query.exec_()
254
255 sig = ""
256
257 if not self.__aborted:
258 # step 4: update the file entry
259 query.prepare(self.update_file_stmt)
260 query.bindValue(":lastRead", QDateTime.currentDateTime())
261 query.bindValue(":file", apiFile)
262 query.exec_()
263 finally:
264 del query
265 if self.__aborted:
266 db.rollback()
267 else:
268 db.commit()
269
270 def __deleteApiFile(self, apiFile):
271 """
272 Private method to delete all references to an api file.
273
274 @param apiFile filename of the raw API file (string)
275 """
276 db = QSqlDatabase.database(self.__language)
277 db.transaction()
278 try:
279 query = QSqlQuery(db)
280
281 # step 1: get the ID belonging to the api file
282 query.prepare(self.file_id_stmt)
283 query.bindValue(":file", apiFile)
284 query.exec_()
285 query.next()
286 id = int(query.value(0))
287
288 # step 2: delete all api entries belonging to this file
289 query.prepare(self.populate_del_api_stmt)
290 query.bindValue(":fileId", id)
291 query.exec_()
292
293 # step 3: delete the file entry
294 query.prepare(self.file_delete_id_stmt)
295 query.bindValue(":id", id)
296 query.exec_()
297 finally:
298 del query
299 db.commit()
300
301 def run(self):
302 """
303 Public method to perform the threads work.
304 """
305 QCoreApplication.postEvent(self.__proxy, QEvent(QEvent.Type(WorkerStarted)))
306
307 db = QSqlDatabase.database(self.__language)
308 if db.isValid() and db.isOpen():
309 # step 1: remove API files not wanted any longer
310 loadedApiFiles = self.__proxy.getApiFiles()
311 for apiFile in loadedApiFiles:
312 if not self.__aborted and apiFile not in self.__apiFiles:
313 self.__deleteApiFile(apiFile)
314
315 # step 2: (re-)load api files
316 for apiFile in self.__apiFiles:
317 if not self.__aborted:
318 self.__loadApiFileIfNewer(apiFile)
319
320 if self.__aborted:
321 QCoreApplication.postEvent(self.__proxy, QEvent(QEvent.Type(WorkerAborted)))
322 else:
323 QCoreApplication.postEvent(self.__proxy, QEvent(QEvent.Type(WorkerFinished)))
324
325 class DbAPIs(QObject):
326 """
327 Class implementing an API storage entity.
328
329 @signal apiPreparationFinished() emitted after the API preparation has finished
330 @signal apiPreparationStarted() emitted after the API preparation has started
331 @signal apiPreparationCancelled() emitted after the API preparation has been
332 cancelled
333 """
334 DB_VERSION = 3
335
336 create_mgmt_stmt = """
337 CREATE TABLE mgmt
338 (format INTEGER)
339 """
340 drop_mgmt_stmt = """DROP TABLE IF EXISTS mgmt"""
341
342 create_api_stmt = """
343 CREATE TABLE api
344 (acWord TEXT,
345 context TEXT,
346 fullContext TEXT,
347 signature TEXT,
348 fileId INTEGER,
349 pictureId INTEGER,
350 UNIQUE(acWord, fullContext, signature) ON CONFLICT IGNORE
351 )
352 """
353 drop_api_stmt = """DROP TABLE IF EXISTS api"""
354
355 create_file_stmt = """
356 CREATE TABLE file
357 (id INTEGER PRIMARY KEY AUTOINCREMENT,
358 file TEXT UNIQUE ON CONFLICT IGNORE,
359 lastRead TIMESTAMP DEFAULT CURRENT_TIMESTAMP
360 )
361 """
362 drop_file_stmt = """DROP TABLE IF EXISTS file"""
363
364 create_acWord_idx = """CREATE INDEX acWord_idx on api (acWord)"""
365 drop_acWord_idx = """DROP INDEX IF EXISTS acWord_idx"""
366
367 create_context_idx = """CREATE INDEX context_idx on api (context)"""
368 drop_context_idx = """DROP INDEX IF EXISTS context_idx"""
369
370 create_fullContext_idx = """CREATE INDEX fullContext_idx on api (fullContext)"""
371 drop_fullContext_idx = """DROP INDEX IF EXISTS fullContext_idx"""
372
373 create_file_idx = """CREATE INDEX file_idx on file (file)"""
374 drop_file_idx = """DROP INDEX IF EXISTS file_idx"""
375
376 api_files_stmt = """
377 SELECT file FROM file WHERE file LIKE '%.api'
378 """
379
380 ac_stmt = """
381 SELECT DISTINCT acWord, fullContext, pictureId FROM api
382 WHERE acWord GLOB :acWord
383 ORDER BY acWord
384 """
385 ac_context_stmt = """
386 SELECT DISTINCT acWord, fullContext, pictureId FROM api
387 WHERE context = :context
388 ORDER BY acWord
389 """
390 ct_stmt = """
391 SELECT DISTINCT acWord, signature, fullContext FROM api
392 WHERE acWord = :acWord
393 """
394 ct_context_stmt = """
395 SELECT DISTINCT acWord, signature, fullContext FROM api
396 WHERE acWord = :acWord
397 AND context = :context
398 """
399 ct_fullContext_stmt = """
400 SELECT DISTINCT acWord, signature, fullContext FROM api
401 WHERE acWord = :acWord
402 AND fullContext = :fullContext
403 """
404 format_select_stmt = """
405 SELECT format FROM mgmt
406 """
407 mgmt_insert_stmt = """
408 INSERT INTO mgmt (format) VALUES (%d)
409 """ % DB_VERSION
410
411 def __init__(self, language, parent = None):
412 """
413 Constructor
414
415 @param language language of the APIs object (string)
416 @param parent reference to the parent object (QObject)
417 """
418 QObject.__init__(self, parent)
419 self.setObjectName("DbAPIs_%s" % language)
420
421 self.__inPreparation = False
422 self.__worker = None
423 self.__workerQueue = []
424
425 self.__language = language
426 if self.__language == ApisNameProject:
427 self.__initAsProject()
428 else:
429 self.__initAsLanguage()
430
431 def __initAsProject(self):
432 """
433 Private method to initialize as a project API object.
434 """
435 self.__lexer = None
436
437 self.__project = e5App().getObject("Project")
438 self.connect(self.__project, SIGNAL("projectOpened"), self.__projectOpened)
439 self.connect(self.__project, SIGNAL("newProject"), self.__projectOpened)
440 self.connect(self.__project, SIGNAL("projectClosed"), self.__projectClosed)
441 if self.__project.isOpen():
442 self.__projectOpened()
443
444 def __initAsLanguage(self):
445 """
446 Private method to initialize as a language API object.
447 """
448 if self.__language in ["Python", "Python3"]:
449 self.__discardFirst = "self"
450 else:
451 self.__discardFirst = ""
452 self.__lexer = QScintilla.Lexers.getLexer(self.__language)
453 self.__apifiles = Preferences.getEditorAPI(self.__language)
454 self.__apifiles.sort()
455 if self.__lexer is not None:
456 self.__openAPIs()
457
458 def _apiDbName(self):
459 """
460 Protected method to determine the name of the database file.
461
462 @return name of the database file (string)
463 """
464 if self.__language == ApisNameProject:
465 return os.path.join(self.__project.getProjectManagementDir(),
466 "project-apis.db")
467 else:
468 return os.path.join(Utilities.getConfigDir(), "%s-api.db" % self.__language)
469
470 def close(self):
471 """
472 Public method to close the database.
473 """
474 self.__workerQueue = []
475 if self.__worker is not None:
476 self.__worker.abort()
477 if self.__worker is not None:
478 self.__worker.wait(5000)
479 if self.__worker is not None and \
480 not self.__worker.isFinished():
481 self.__worker.terminate()
482 if self.__worker is not None:
483 self.__worker.wait(5000)
484
485 QSqlDatabase.database(self.__language).close()
486 QSqlDatabase.removeDatabase(self.__language)
487
488 def __openApiDb(self):
489 """
490 Private method to open the API database.
491 """
492 db = QSqlDatabase.database(self.__language, False)
493 if not db.isValid():
494 # the database connection is a new one
495 db = QSqlDatabase.addDatabase("QSQLITE", self.__language)
496 db.setDatabaseName(self._apiDbName())
497 db.open()
498
499 def __createApiDB(self):
500 """
501 Private method to create an API database.
502 """
503 db = QSqlDatabase.database(self.__language)
504 db.transaction()
505 try:
506 query = QSqlQuery(db)
507 # step 1: drop old tables
508 query.exec_(self.drop_mgmt_stmt)
509 query.exec_(self.drop_api_stmt)
510 query.exec_(self.drop_file_stmt)
511 # step 2: drop old indices
512 query.exec_(self.drop_acWord_idx)
513 query.exec_(self.drop_context_idx)
514 query.exec_(self.drop_fullContext_idx)
515 query.exec_(self.drop_file_idx)
516 # step 3: create tables
517 query.exec_(self.create_api_stmt)
518 query.exec_(self.create_file_stmt)
519 query.exec_(self.create_mgmt_stmt)
520 query.exec_(self.mgmt_insert_stmt)
521 # step 4: create indices
522 query.exec_(self.create_acWord_idx)
523 query.exec_(self.create_context_idx)
524 query.exec_(self.create_fullContext_idx)
525 query.exec_(self.create_file_idx)
526 finally:
527 del query
528 db.commit()
529
530 def getApiFiles(self):
531 """
532 Public method to get a list of API files loaded into the database.
533
534 @return list of API filenames (list of strings)
535 """
536 apiFiles = []
537
538 db = QSqlDatabase.database(self.__language)
539 db.transaction()
540 try:
541 query = QSqlQuery(db)
542 query.exec_(self.api_files_stmt)
543 while query.next():
544 apiFiles.append(query.value(0))
545 finally:
546 del query
547 db.commit()
548
549 return apiFiles
550
551 def __isPrepared(self):
552 """
553 Private method to check, if the database has been prepared.
554
555 @return flag indicating the prepared status (boolean)
556 """
557 db = QSqlDatabase.database(self.__language)
558 prepared = len(db.tables()) > 0
559 if prepared:
560 db.transaction()
561 prepared = False
562 try:
563 query = QSqlQuery(db)
564 ok = query.exec_(self.format_select_stmt)
565 if ok:
566 query.next()
567 format = int(query.value(0))
568 if format >= self.DB_VERSION:
569 prepared = True
570 finally:
571 del query
572 db.commit()
573 return prepared
574
575 def getCompletions(self, start = None, context = None):
576 """
577 Public method to determine the possible completions.
578
579 @keyparam start string giving the start of the word to be
580 completed (string)
581 @keyparam context string giving the context (e.g. classname)
582 to be completed (string)
583 @return list of dictionaries with possible completions (key 'completion'
584 contains the completion (string), key 'context'
585 contains the context (string) and key 'pictureId'
586 contains the ID of the icon to be shown (string))
587 """
588 completions = []
589
590 db = QSqlDatabase.database(self.__language)
591 if db.isOpen() and not self.__inPreparation:
592 db.transaction()
593 try:
594 query = None
595
596 if start is not None:
597 query = QSqlQuery(db)
598 query.prepare(self.ac_stmt)
599 query.bindValue(":acWord", start + '*')
600 elif context is not None:
601 query = QSqlQuery(db)
602 query.prepare(self.ac_context_stmt)
603 query.bindValue(":context", context)
604
605 if query is not None:
606 query.exec_()
607 while query.next():
608 completions.append({"completion" : query.value(0),
609 "context" : query.value(1),
610 "pictureId" : query.value(2)})
611 del query
612 finally:
613 db.commit()
614
615 return completions
616
617 def getCalltips(self, acWord, commas, context = None, fullContext = None,
618 showContext = True):
619 """
620 Public method to determine the calltips.
621
622 @param acWord function to get calltips for (string)
623 @param commas minimum number of commas contained in the calltip (integer)
624 @param context string giving the context (e.g. classname) (string)
625 @param fullContext string giving the full context (string)
626 @param showContext flag indicating to show the calltip context (boolean)
627 @return list of calltips (list of string)
628 """
629 calltips = []
630
631 db = QSqlDatabase.database(self.__language)
632 if db.isOpen() and not self.__inPreparation:
633 if self.autoCompletionWordSeparators():
634 contextSeparator = self.autoCompletionWordSeparators()[0]
635 else:
636 contextSeparator = " "
637 db.transaction()
638 try:
639 query = QSqlQuery(db)
640 if fullContext:
641 query.prepare(self.ct_fullContext_stmt)
642 query.bindValue(":fullContext", fullContext)
643 elif context:
644 query.prepare(self.ct_context_stmt)
645 query.bindValue(":context", context)
646 else:
647 query.prepare(self.ct_stmt)
648 query.bindValue(":acWord", acWord)
649 query.exec_()
650 while query.next():
651 word = query.value(0)
652 sig = query.value(1)
653 fullCtx = query.value(2)
654 if sig:
655 if self.__discardFirst:
656 sig = "(%s" % sig[1:]\
657 .replace(self.__discardFirst, "", 1)\
658 .strip(", \t\r\n")
659 if self.__enoughCommas(sig, commas):
660 if showContext:
661 calltips.append("%s%s%s%s" % \
662 (fullCtx, contextSeparator, word, sig))
663 else:
664 calltips.append("%s%s" % (word, sig))
665 del query
666 finally:
667 db.commit()
668
669 if context and len(calltips) == 0:
670 # nothing found, try without a context
671 calltips = self.getCalltips(acWord, commas, showContext = showContext)
672
673 return calltips
674
675 def __enoughCommas(self, s, commas):
676 """
677 Private method to determine, if the given string contains enough commas.
678
679 @param s string to check (string)
680 @param commas number of commas to check for (integer)
681 @return flag indicating, that there are enough commas (boolean)
682 """
683 end = s.find(')')
684
685 if end < 0:
686 return False
687
688 w = s[:end]
689 return w.count(',') >= commas
690
691 def __openAPIs(self):
692 """
693 Private method to open the API database.
694 """
695 self.__openApiDb()
696 if not self.__isPrepared():
697 self.__createApiDB()
698
699 # prepare the database if neccessary
700 self.prepareAPIs()
701
702 def prepareAPIs(self, rawList = None):
703 """
704 Public method to prepare the APIs if neccessary.
705
706 @keyparam rawList list of raw API files (list of strings)
707 """
708 if self.__inPreparation:
709 return
710
711 projectPath = ""
712 if rawList:
713 apiFiles = rawList[:]
714 elif self.__language == ApisNameProject:
715 apiFiles = self.__project.getSources()
716 projectPath = self.__project.getProjectPath()
717 else:
718 apiFiles = Preferences.getEditorAPI(self.__language)
719 self.__worker = DbAPIsWorker(self, self.__language, apiFiles, projectPath)
720 self.__worker.start()
721
722 def __processQueue(self):
723 """
724 Private slot to process the queue of files to load.
725 """
726 if self.__worker is not None and self.__worker.isFinished():
727 self.__worker = None
728
729 if self.__worker is None and len(self.__workerQueue) > 0:
730 apiFiles = [self.__workerQueue.pop(0)]
731 if self.__language == ApisNameProject:
732 projectPath = self.__project.getProjectPath()
733 apiFiles = [apiFiles[0].replace(projectPath + os.sep, "")]
734 else:
735 projectPath = ""
736 self.__worker = DbAPIsWorker(self, self.__language, apiFiles, projectPath)
737 self.__worker.start()
738
739 def getLexer(self):
740 """
741 Public method to return a reference to our lexer object.
742
743 @return reference to the lexer object (QScintilla.Lexers.Lexer)
744 """
745 return self.__lexer
746
747 def autoCompletionWordSeparators(self):
748 """
749 Private method to get the word separator characters.
750
751 @return word separator characters (list of strings)
752 """
753 if self.__lexer:
754 return self.__lexer.autoCompletionWordSeparators()
755 return None
756
757 def event(self, evt):
758 """
759 Protected method to handle events from the worker thread.
760
761 @param evt reference to the event object (QEvent)
762 @return flag indicating, if the event was handled (boolean)
763 """
764 if evt.type() == WorkerStarted:
765 self.__inPreparation = True
766 self.emit(SIGNAL('apiPreparationStarted()'))
767 return True
768
769 elif evt.type() == WorkerFinished:
770 self.__inPreparation = False
771 self.emit(SIGNAL('apiPreparationFinished()'))
772 QTimer.singleShot(0, self.__processQueue)
773 return True
774
775 elif evt.type() == WorkerAborted:
776 self.__inPreparation = False
777 self.emit(SIGNAL('apiPreparationCancelled()'))
778 QTimer.singleShot(0, self.__processQueue)
779 return True
780
781 else:
782 return QObject.event(self, evt)
783
784 ########################################################
785 ## project related stuff below
786 ########################################################
787
788 def __projectOpened(self):
789 """
790 Private slot to perform actions after a project has been opened.
791 """
792 if self.__project.getProjectLanguage() in ["Python", "Python3"]:
793 self.__discardFirst = "self"
794 else:
795 self.__discardFirst = ""
796 self.__lexer = QScintilla.Lexers.getLexer(self.__project.getProjectLanguage())
797 self.__openAPIs()
798
799 def __projectClosed(self):
800 """
801 Private slot to perform actions after a project has been closed.
802 """
803 self.close()
804
805 def editorSaved(self, filename):
806 """
807 Public slot to handle the editorSaved signal.
808
809 @param filename name of the file that was saved (string)
810 """
811 if self.__project.isProjectSource(filename):
812 self.__workerQueue.append(filename)
813 self.__processQueue()
814
815 class APIsManager(QObject):
816 """
817 Class implementing the APIsManager class, which is the central store for
818 API information used by autocompletion and calltips.
819 """
820 def __init__(self, parent = None):
821 """
822 Constructor
823
824 @param parent reference to the parent object (QObject)
825 """
826 QObject.__init__(self, parent)
827 self.setObjectName("APIsManager")
828
829 # initialize the apis dictionary
830 self.__apis = {}
831
832 def reloadAPIs(self):
833 """
834 Public slot to reload the api information.
835 """
836 for api in list(self.__apis.values()):
837 api and api.prepareAPIs()
838
839 def getAPIs(self, language):
840 """
841 Public method to get an apis object for autocompletion/calltips.
842
843 This method creates and loads an APIs object dynamically upon request.
844 This saves memory for languages, that might not be needed at the moment.
845
846 @param language the language of the requested api object (string)
847 @return the apis object (APIs)
848 """
849 try:
850 return self.__apis[language]
851 except KeyError:
852 if language in QScintilla.Lexers.getSupportedLanguages() or \
853 language == ApisNameProject:
854 # create the api object
855 self.__apis[language] = DbAPIs(language)
856 return self.__apis[language]
857 else:
858 return None
859
860 def deactivate(self):
861 """
862 Public method to perform actions upon deactivation.
863 """
864 for apiLang in self.__apis:
865 self.__apis[apiLang].close()
866 self.__apis[apiLang] = None

eric ide

mercurial