AssistantEric/APIsManager.py

changeset 71
025683852a63
parent 69
9082f14126d9
child 74
9ac338de7a2b
child 76
add31149e0b1
--- a/AssistantEric/APIsManager.py	Tue Apr 02 19:33:12 2013 +0200
+++ b/AssistantEric/APIsManager.py	Wed Apr 03 18:34:47 2013 +0200
@@ -9,8 +9,7 @@
 
 import os
 
-from PyQt4.QtCore import QTimer, QThread, QFileInfo, pyqtSignal, QCoreApplication, \
-     QEvent, QDateTime, QObject, Qt
+from PyQt4.QtCore import QTimer, QThread, QFileInfo, pyqtSignal, QDateTime, QObject, Qt
 try:
     from PyQt4.QtSql import QSqlDatabase, QSqlQuery
 except ImportError:
@@ -25,9 +24,10 @@
 import Utilities
 import Preferences
 
-WorkerStarted = QEvent.User + 2001
-WorkerFinished = QEvent.User + 2002
-WorkerAborted = QEvent.User + 2003
+WorkerStatusStarted = 2001
+WorkerStatusFinished = 2002
+WorkerStatusAborted = 2003
+WorkerStatusFile = 2004
 
 ApisNameProject = "__Project__"
 
@@ -35,7 +35,12 @@
 class DbAPIsWorker(QThread):
     """
     Class implementing a worker thread to prepare the API database.
+    
+    @signal processing(status, file) emitted to indicate the processing status
+            (one of WorkerStatus..., string)
     """
+    processing = pyqtSignal(int, str)
+    
     populate_api_stmt = """
         INSERT INTO api (acWord, context, fullContext, signature, fileId, pictureId)
         VALUES (:acWord, :context, :fullContext, :signature, :fileId, :pictureId)
@@ -144,6 +149,7 @@
                 if modTimeBases > modTime:
                     modTime = modTimeBases
         if loadTime < modTime:
+            self.processing.emit(WorkerStatusFile, apiFile)
             self.__loadApiFile(apiFile)
     
     def __classesAttributesApi(self, module):
@@ -221,6 +227,37 @@
         
         if len(apis) > 0:
             self.__storeApis(apis, bases, apiFile, language)
+        else:
+            # just store file info to avoid rereading it every time
+            self.__storeFileInfoOnly(apiFile)
+    
+    def __storeFileInfoOnly(self, apiFile):
+        """
+        Private method to store file info only.
+        
+        Doing this avoids rereading the file whenever the API is initialized in case
+        the given file doesn't contain API data.
+        """
+        db = QSqlDatabase.database(self.__language)
+        db.transaction()
+        try:
+            query = QSqlQuery(db)
+            # step 1: create entry in file table
+            query.prepare(self.populate_file_stmt)
+            query.bindValue(":file", apiFile)
+            query.exec_()
+            
+            # step 2: update the file entry
+            query.prepare(self.update_file_stmt)
+            query.bindValue(":lastRead", QDateTime.currentDateTime())
+            query.bindValue(":file", apiFile)
+            query.exec_()
+        finally:
+            del query
+            if self.__aborted:
+                db.rollback()
+            else:
+                db.commit()
     
     def __storeApis(self, apis, bases, apiFile, language):
         """
@@ -341,7 +378,7 @@
                 query.exec_()
             
             if not self.__aborted:
-                # step 4: update the file entry
+                # step 5: update the file entry
                 query.prepare(self.update_file_stmt)
                 query.bindValue(":lastRead", QDateTime.currentDateTime())
                 query.bindValue(":file", apiFile)
@@ -393,7 +430,7 @@
         """
         Public method to perform the threads work.
         """
-        QCoreApplication.postEvent(self.__proxy, QEvent(QEvent.Type(WorkerStarted)))
+        self.processing.emit(WorkerStatusStarted, "")
         
         db = QSqlDatabase.database(self.__language)
         if db.isValid() and db.isOpen():
@@ -410,23 +447,19 @@
                     self.__loadApiFileIfNewer(apiFile)
         
         if self.__aborted:
-            QCoreApplication.postEvent(self.__proxy, QEvent(QEvent.Type(WorkerAborted)))
+            self.processing.emit(WorkerStatusAborted, "")
         else:
-            QCoreApplication.postEvent(self.__proxy, QEvent(QEvent.Type(WorkerFinished)))
+            self.processing.emit(WorkerStatusFinished, "")
 
 
 class DbAPIs(QObject):
     """
     Class implementing an API storage entity.
     
-    @signal apiPreparationFinished(language) emitted after the API preparation has finished
-    @signal apiPreparationStarted(language) emitted after the API preparation has started
-    @signal apiPreparationCancelled(language) emitted after the API preparation has been
-            cancelled
+    @signal apiPreparationStatus(language, status, file) emitted to indicate the
+            API preparation status for a language
     """
-    apiPreparationFinished = pyqtSignal(str)
-    apiPreparationStarted = pyqtSignal(str)
-    apiPreparationCancelled = pyqtSignal(str)
+    apiPreparationStatus = pyqtSignal(str, int, str)
     
     DB_VERSION = 4
     
@@ -910,6 +943,7 @@
         else:
             apiFiles = Preferences.getEditorAPI(self.__language)
         self.__worker = DbAPIsWorker(self, self.__language, apiFiles, projectPath)
+        self.__worker.processing.connect(self.__processingStatus, Qt.QueuedConnection)
         self.__worker.start()
     
     def __processQueue(self):
@@ -917,6 +951,7 @@
         Private slot to process the queue of files to load.
         """
         if self.__worker is not None and self.__worker.isFinished():
+            self.__worker.deleteLater()
             self.__worker = None
         
         if self.__worker is None and len(self.__workerQueue) > 0:
@@ -928,6 +963,7 @@
                 projectPath = ""
             self.__worker = DbAPIsWorker(self, self.__language, apiFiles, projectPath,
                                          refresh=True)
+            self.__worker.processing.connect(self.__processingStatus, Qt.QueuedConnection)
             self.__worker.start()
     
     def getLexer(self):
@@ -948,32 +984,27 @@
             return self.__lexer.autoCompletionWordSeparators()
         return None
     
-    def event(self, evt):
+    def __processingStatus(self, status, filename):
         """
-        Protected method to handle events from the worker thread.
-        
-        @param evt reference to the event object (QEvent)
-        @return flag indicating, if the event was handled (boolean)
-        """
-        if evt.type() == WorkerStarted:
-            self.__inPreparation = True
-            self.apiPreparationStarted.emit(self.__language)
-            return True
+        Private slot handling the processing signal of the API preparation
+        thread.
         
-        elif evt.type() == WorkerFinished:
+        @param status preparation status (integer, one of WorkerStatus...)
+        @param filename name of the file being processed (string)
+        """
+        if status == WorkerStatusStarted:
+            self.__inPreparation = True
+            self.apiPreparationStatus.emit(self.__language, WorkerStatusStarted, "")
+        elif status == WorkerStatusFinished:
             self.__inPreparation = False
-            self.apiPreparationFinished.emit(self.__language)
+            self.apiPreparationStatus.emit(self.__language, WorkerStatusFinished, "")
             QTimer.singleShot(0, self.__processQueue)
-            return True
-        
-        elif evt.type() == WorkerAborted:
+        elif status == WorkerStatusAborted:
             self.__inPreparation = False
-            self.apiPreparationCancelled.emit(self.__language)
+            self.apiPreparationStatus.emit(self.__language, WorkerStatusAborted, "")
             QTimer.singleShot(0, self.__processQueue)
-            return True
-        
-        else:
-            return QObject.event(self,  evt)
+        elif status == WorkerStatusFile:
+            self.apiPreparationStatus.emit(self.__language, WorkerStatusFile, filename)
     
     ########################################################
     ## project related stuff below
@@ -1060,9 +1091,7 @@
                language == ApisNameProject:
                 # create the api object
                 api = DbAPIs(language)
-                api.apiPreparationFinished.connect(self.__apiPreparationFinished)
-                api.apiPreparationStarted.connect(self.__apiPreparationStarted)
-                api.apiPreparationCancelled.connect(self.__apiPreparationCancelled)
+                api.apiPreparationStatus.connect(self.__apiPreparationStatus)
                 self.__apis[language] = api
                 return self.__apis[language]
             else:
@@ -1083,7 +1112,8 @@
         
         @param msg message to be shown (string)
         """
-        self.__mw.statusBar().showMessage(msg, 2000)
+        if msg:
+            self.__mw.statusBar().showMessage(msg, 2000)
     
     def __apiPreparationFinished(self, language):
         """
@@ -1117,3 +1147,27 @@
             language = self.trUtf8("Project")
         self.__showMessage(self.trUtf8("Preparation of '{0}' APIs cancelled.")
             .format(language))
+    
+    def __apiPreparationStatus(self, language, status, filename):
+        """
+        Private slot handling the preparation status signal of an API object.
+        
+        @param language language of the API (string)
+        @param status preparation status (integer, one of WorkerStatus...)
+        @param filename name of the file being processed (string)
+        """
+        if language == ApisNameProject:
+            language = self.trUtf8("Project")
+        
+        if status == WorkerStatusStarted:
+            self.__showMessage(self.trUtf8("Preparation of '{0}' APIs started.").format(
+                language))
+        elif status == WorkerStatusFile:
+            self.__showMessage(self.trUtf8("'{0}' APIs: Processing '{1}'").format(
+                language, os.path.basename(filename)))
+        elif status == WorkerStatusFinished:
+            self.__showMessage(self.trUtf8("Preparation of '{0}' APIs finished.").format(
+                language))
+        elif status == WorkerStatusAborted:
+            self.__showMessage(self.trUtf8("Preparation of '{0}' APIs cancelled.").format(
+                language))

eric ide

mercurial