eric6/QScintilla/APIsManager.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7229
53054eb5b15a
diff -r f99d60d6b59b -r 2602857055c5 eric6/QScintilla/APIsManager.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/QScintilla/APIsManager.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,296 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2007 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the APIsManager.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt5.QtCore import QDir, QFileInfo, pyqtSignal, QObject
+from PyQt5.Qsci import QsciAPIs
+
+from . import Lexers
+import Preferences
+import Globals
+
+
+class APIs(QObject):
+    """
+    Class implementing an API storage entity.
+    
+    @signal apiPreparationFinished() emitted after the API preparation has
+        finished
+    @signal apiPreparationCancelled() emitted after the API preparation has
+        been cancelled
+    @signal apiPreparationStarted() emitted after the API preparation has
+        started
+    """
+    apiPreparationFinished = pyqtSignal()
+    apiPreparationCancelled = pyqtSignal()
+    apiPreparationStarted = pyqtSignal()
+    
+    def __init__(self, language, projectType="", forPreparation=False,
+                 parent=None):
+        """
+        Constructor
+        
+        @param language language of the APIs object
+        @type str
+        @param projectType type of the project
+        @type str
+        @param forPreparation flag indicating this object is just needed
+            for a preparation process
+        @type bool
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super(APIs, self).__init__(parent)
+        if projectType:
+            self.setObjectName("APIs_{0}_{1}".format(language, projectType))
+        else:
+            self.setObjectName("APIs_{0}".format(language))
+        
+        self.__inPreparation = False
+        self.__language = language
+        self.__projectType = projectType
+        self.__forPreparation = forPreparation
+        self.__lexer = Lexers.getLexer(self.__language)
+        self.__apifiles = Preferences.getEditorAPI(self.__language,
+                                                   self.__projectType)
+        self.__apifiles.sort()
+        if self.__lexer is None:
+            self.__apis = None
+        else:
+            self.__apis = QsciAPIs(self.__lexer)
+            self.__apis.apiPreparationFinished.connect(
+                self.__apiPreparationFinished)
+            self.__apis.apiPreparationCancelled.connect(
+                self.__apiPreparationCancelled)
+            self.__apis.apiPreparationStarted.connect(
+                self.__apiPreparationStarted)
+            self.__loadAPIs()
+        
+    def __loadAPIs(self):
+        """
+        Private method to load the APIs.
+        """
+        if self.__apis.isPrepared():
+            # load a prepared API file
+            if not self.__forPreparation and \
+                    Preferences.getEditor("AutoPrepareAPIs"):
+                self.prepareAPIs()
+            self.__apis.loadPrepared(self.__preparedName())
+        else:
+            # load the raw files and prepare the API file
+            if not self.__forPreparation and \
+                    Preferences.getEditor("AutoPrepareAPIs"):
+                self.prepareAPIs(ondemand=True)
+    
+    def reloadAPIs(self):
+        """
+        Public method to reload the API information.
+        """
+        if not self.__forPreparation and \
+                Preferences.getEditor("AutoPrepareAPIs"):
+            self.prepareAPIs()
+        self.__loadAPIs()
+    
+    def getQsciAPIs(self):
+        """
+        Public method to get a reference to QsciAPIs object.
+        
+        @return reference to the QsciAPIs object (QsciAPIs)
+        """
+        if not self.__forPreparation and \
+                Preferences.getEditor("AutoPrepareAPIs"):
+            self.prepareAPIs()
+        return self.__apis
+    
+    def isEmpty(self):
+        """
+        Public method to check, if the object has API files configured.
+        
+        @return flag indicating no API files have been configured (boolean)
+        """
+        return len(self.__apifiles) == 0
+    
+    def __apiPreparationFinished(self):
+        """
+        Private method called to save an API, after it has been prepared.
+        """
+        self.__apis.savePrepared(self.__preparedName())
+        self.__inPreparation = False
+        self.apiPreparationFinished.emit()
+    
+    def __apiPreparationCancelled(self):
+        """
+        Private method called, after the API preparation process has been
+        cancelled.
+        """
+        self.__inPreparation = False
+        self.apiPreparationCancelled.emit()
+    
+    def __apiPreparationStarted(self):
+        """
+        Private method called, when the API preparation process started.
+        """
+        self.__inPreparation = True
+        self.apiPreparationStarted.emit()
+    
+    def prepareAPIs(self, ondemand=False, rawList=None):
+        """
+        Public method to prepare the APIs if necessary.
+        
+        @keyparam ondemand flag indicating a requested preparation (boolean)
+        @keyparam rawList list of raw API files (list of strings)
+        """
+        if self.__apis is None or self.__inPreparation:
+            return
+        
+        needsPreparation = False
+        if ondemand:
+            needsPreparation = True
+        else:
+            # check, if a new preparation is necessary
+            preparedAPIs = self.__preparedName()
+            if preparedAPIs:
+                preparedAPIsInfo = QFileInfo(preparedAPIs)
+                if not preparedAPIsInfo.exists():
+                    needsPreparation = True
+                else:
+                    preparedAPIsTime = preparedAPIsInfo.lastModified()
+                    apifiles = sorted(Preferences.getEditorAPI(
+                        self.__language, self.__projectType))
+                    if self.__apifiles != apifiles:
+                        needsPreparation = True
+                    for apifile in apifiles:
+                        if QFileInfo(apifile).lastModified() > \
+                                preparedAPIsTime:
+                            needsPreparation = True
+                            break
+        
+        if needsPreparation:
+            # do the preparation
+            self.__apis.clear()
+            if rawList:
+                apifiles = rawList
+            else:
+                apifiles = Preferences.getEditorAPI(
+                    self.__language, self.__projectType)
+            for apifile in apifiles:
+                self.__apis.load(apifile)
+            self.__apis.prepare()
+            self.__apifiles = apifiles
+    
+    def cancelPreparation(self):
+        """
+        Public slot to cancel the APIs preparation.
+        """
+        self.__apis and self.__apis.cancelPreparation()
+    
+    def installedAPIFiles(self):
+        """
+        Public method to get a list of installed API files.
+        
+        @return list of installed API files (list of strings)
+        """
+        if self.__apis is not None:
+            if Globals.isWindowsPlatform():
+                qsciPath = os.path.join(
+                    Globals.getPyQt5ModulesDirectory(), "qsci")
+                if os.path.exists(qsciPath):
+                    # it's the installer
+                    if self.__lexer.lexerName() is not None:
+                        apidir = os.path.join(qsciPath, "api",
+                                              self.__lexer.lexerName())
+                        fnames = []
+                        filist = QDir(apidir).entryInfoList(
+                            ["*.api"], QDir.Files, QDir.IgnoreCase)
+                        for fi in filist:
+                            fnames.append(fi.absoluteFilePath())
+                        return fnames
+                    else:
+                        return []
+            
+            return self.__apis.installedAPIFiles()
+        else:
+            return []
+    
+    def __preparedName(self):
+        """
+        Private method returning the default name of a prepared API file.
+        
+        @return complete filename for the Prepared APIs file (string)
+        """
+        apisDir = os.path.join(Globals.getConfigDir(), "APIs")
+        if self.__apis is not None:
+            if self.__projectType:
+                filename = "{0}_{1}.pap".format(self.__language,
+                                                self.__projectType)
+            else:
+                filename = "{0}.pap".format(self.__language)
+            return os.path.join(apisDir, filename)
+        else:
+            return ""
+    
+
+class APIsManager(QObject):
+    """
+    Class implementing the APIsManager class, which is the central store for
+    API information used by autocompletion and calltips.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent object (QObject)
+        """
+        super(APIsManager, self).__init__(parent)
+        self.setObjectName("APIsManager")
+        
+        self.__apis = {}
+    
+    def reloadAPIs(self):
+        """
+        Public slot to reload the api information.
+        """
+        for api in list(self.__apis.values()):
+            api and api.reloadAPIs()
+    
+    def getAPIs(self, language, projectType="", forPreparation=False):
+        """
+        Public method to get an APIs object for autocompletion/calltips.
+        
+        This method creates and loads an APIs object dynamically upon request.
+        This saves memory for languages, that might not be needed at the
+        moment.
+        
+        @param language language of the requested APIs object
+        @type str
+        @param projectType type of the project
+        @type str
+        @param forPreparation flag indicating the requested APIs object is just
+            needed for a preparation process
+        @type bool
+        @return reference to the APIs object
+        @rtype APIs
+        """
+        if forPreparation:
+            return APIs(language, projectType=projectType,
+                        forPreparation=forPreparation)
+        else:
+            try:
+                return self.__apis[(language, projectType)]
+            except KeyError:
+                if language in Lexers.getSupportedApiLanguages():
+                    # create the api object
+                    self.__apis[(language, projectType)] = \
+                        APIs(language, projectType=projectType)
+                    return self.__apis[(language, projectType)]
+                else:
+                    return None

eric ide

mercurial