示例#1
0
    def __init__(self):
        QObject.__init__(self)

        self.dirCache = VCSStatusCache()  # Path -> VCSStatus
        self.fileCache = VCSStatusCache()  # Path -> VCSStatus
        self.activePlugins = {}  # Plugin ID -> VCSPluginDescriptor
        self.systemIndicators = {}  # ID -> VCSIndicator

        self.__firstFreeIndex = 0

        self.__readSettingsIndicators()
        self.__dirRequestLoopTimer = QTimer(self)
        self.__dirRequestLoopTimer.setSingleShot(True)
        self.__dirRequestLoopTimer.timeout.connect(self.__onDirRequestLoopTimer)

        GlobalData().project.projectChanged.connect(self.__onProjectChanged)
        GlobalData().project.fsChanged.connect(self.__onFSChanged)
        self.connect(GlobalData().pluginManager, SIGNAL("PluginActivated"), self.__onPluginActivated)

        # Plugin deactivation must be done via dismissPlugin(...)
        return
示例#2
0
    def __init__(self):
        QObject.__init__(self)

        self.dirCache = VCSStatusCache()  # Path -> VCSStatus
        self.fileCache = VCSStatusCache()  # Path -> VCSStatus
        self.activePlugins = {}  # Plugin ID -> VCSPluginDescriptor
        self.systemIndicators = {}  # ID -> VCSIndicator

        self.__firstFreeIndex = 0

        self.__readSettingsIndicators()
        self.__dirRequestLoopTimer = QTimer(self)
        self.__dirRequestLoopTimer.setSingleShot(True)
        self.__dirRequestLoopTimer.timeout.connect(
            self.__onDirRequestLoopTimer)

        GlobalData().project.projectChanged.connect(self.__onProjectChanged)
        GlobalData().project.fsChanged.connect(self.__onFSChanged)
        self.connect(GlobalData().pluginManager, SIGNAL('PluginActivated'),
                     self.__onPluginActivated)

        # Plugin deactivation must be done via dismissPlugin(...)
        return
示例#3
0
class VCSManager(QObject):
    """ Manages the VCS plugins.
        It sends two signals:
        VCSFileStatus -> path, pluginID, indicatorID, message
        VCSDirStatus -> path, pluginID, indicatorID, message
            The pluginID, indicatorID, message could be None
    """
    def __init__(self):
        QObject.__init__(self)

        self.dirCache = VCSStatusCache()  # Path -> VCSStatus
        self.fileCache = VCSStatusCache()  # Path -> VCSStatus
        self.activePlugins = {}  # Plugin ID -> VCSPluginDescriptor
        self.systemIndicators = {}  # ID -> VCSIndicator

        self.__firstFreeIndex = 0

        self.__readSettingsIndicators()
        self.__dirRequestLoopTimer = QTimer(self)
        self.__dirRequestLoopTimer.setSingleShot(True)
        self.__dirRequestLoopTimer.timeout.connect(
            self.__onDirRequestLoopTimer)

        GlobalData().project.projectChanged.connect(self.__onProjectChanged)
        GlobalData().project.fsChanged.connect(self.__onFSChanged)
        self.connect(GlobalData().pluginManager, SIGNAL('PluginActivated'),
                     self.__onPluginActivated)

        # Plugin deactivation must be done via dismissPlugin(...)
        return

    def __getNewPluginIndex(self):
        " Provides a new plugin index "
        index = self.__firstFreeIndex
        self.__firstFreeIndex += 1
        return index

    def __readSettingsIndicators(self):
        " Reads the system indicators "
        for indicLine in Settings().vcsindicators:
            indicator = VCSIndicator(indicLine)
            self.systemIndicators[indicator.identifier] = indicator
        return

    def __onPluginActivated(self, plugin):
        " Triggered when a plugin is activated "
        if plugin.categoryName != "VersionControlSystemInterface":
            return

        newPluginIndex = self.__getNewPluginIndex()
        self.activePlugins[newPluginIndex] = VCSPluginDescriptor(
            self, newPluginIndex, plugin)
        self.connect(plugin.getObject(), SIGNAL("PathChanged"),
                     self.__onPathChanged)

        # Need to send requests for the opened TAB files
        mainWindow = GlobalData().mainWindow
        editorsManager = mainWindow.editorsManagerWidget.editorsManager
        editorsManager.sendAllTabsVCSStatusRequest()

        if self.activePluginCount() == 1 and GlobalData().project.isLoaded():
            # This is the first plugin and a project is there
            self.__populateProjectDirectories()
        self.__sendDirectoryRequestsOnActivation(newPluginIndex)
        self.__sendFileRequestsOnActivation(newPluginIndex)

        if self.activePluginCount() == 1:
            self.__startDirRequestTimer()
        return

    def __onPathChanged(self, path):
        " The way plugins signal that a path has been changed "
        # What is essentially required is to update the status of the path.
        # setLocallyModified(...) will do - it sends urgent request
        self.setLocallyModified(path)

        # Changed paths may change the file contents
        mainWindow = GlobalData().mainWindow
        editorsManager = mainWindow.editorsManagerWidget.editorsManager
        editorsManager.checkOutsidePathChange(path)
        return

    def __populateProjectDirectories(self):
        " Populates the project directories in the dirCache "
        project = GlobalData().project
        for path in project.filesList:
            if path.endswith(os.path.sep):
                self.dirCache.updateStatus(path, None, None, None, None)
        return

    def __onProjectChanged(self, what):
        " Triggered when a project has changed "
        if what == CodimensionProject.CompleteProject:
            self.dirCache.clear()
            self.fileCache.clear()
            if len(self.activePlugins) == 0:
                return

            # There are some plugins
            for _, descriptor in self.activePlugins.iteritems():
                descriptor.clearRequestQueue()

            if GlobalData().project.isLoaded():
                self.__populateProjectDirectories()
            return

    def __onFSChanged(self, items):
        " Triggered when files/dirs in the project are changed "
        for item in items:
            item = str(item)
            if item.startswith('-'):
                item = item[1:]
                if item.endswith(os.path.sep):
                    # Directory removed
                    if item in self.dirCache.cache:
                        del self.dirCache.cache[item]
                else:
                    # File deleted
                    if item in self.fileCache.cache:
                        del self.fileCache.cache[item]
                    for _, descriptor in self.activePlugins.iteritems():
                        descriptor.requestStatus(
                            item,
                            VersionControlSystemInterface.REQUEST_ITEM_ONLY,
                            True)
            else:
                item = item[1:]
                if item.endswith(os.path.sep):
                    # Directory added
                    if item not in self.dirCache.cache:
                        self.dirCache.updateStatus(item, None, None, None,
                                                   None)
                    for _, descriptor in self.activePlugins.iteritems():
                        descriptor.requestStatus(
                            item,
                            VersionControlSystemInterface.REQUEST_DIRECTORY)
                else:
                    # File added
                    for _, descriptor in self.activePlugins.iteritems():
                        descriptor.requestStatus(
                            item,
                            VersionControlSystemInterface.REQUEST_ITEM_ONLY,
                            True)
        return

    def __sendDirectoryRequestsOnActivation(self, pluginID):
        " Sends the directory requests to the given plugin "
        descriptor = self.activePlugins[pluginID]
        for path, status in self.dirCache.cache.iteritems():
            if status.indicatorID in [
                    None, VersionControlSystemInterface.NOT_UNDER_VCS
            ]:
                descriptor.requestStatus(
                    path, VersionControlSystemInterface.REQUEST_DIRECTORY)
        return

    def __sendFileRequestsOnActivation(self, pluginID):
        " Sends the file requests to the given plugin "
        descriptor = self.activePlugins[pluginID]
        for path, status in self.fileCache.cache.iteritems():
            if status.indicatorID in [
                    None, VersionControlSystemInterface.NOT_UNDER_VCS
            ]:
                descriptor.requestStatus(
                    path, VersionControlSystemInterface.REQUEST_ITEM_ONLY)
        return

    def __sendPeriodicDirectoryRequests(self):
        " Sends the directory requests periodically "
        for path, status in self.dirCache.cache.iteritems():
            if status.pluginID in self.activePlugins:
                # This directory is under certain VCS, send the request
                # only to this VCS
                descriptor = self.activePlugins[status.pluginID]
                descriptor.requestStatus(
                    path, VersionControlSystemInterface.REQUEST_DIRECTORY)
            else:
                # The directory is not under any known VCS. Send the request
                # to all the registered VCS plugins
                for _, descriptor in self.activePlugins.iteritems():
                    descriptor.requestStatus(
                        path, VersionControlSystemInterface.REQUEST_DIRECTORY)
        return

    def dismissAllPlugins(self):
        " Stops all the plugin threads "
        self.__dirRequestLoopTimer.stop()

        for identifier, descriptor in self.activePlugins.iteritems():
            self.disconnect(descriptor.plugin.getObject(),
                            SIGNAL("PathChanged"), self.__onPathChanged)
            descriptor.stopThread()

        self.dirCache.clear()
        self.fileCache.clear()
        self.activePlugins = {}
        return

    def dismissPlugin(self, plugin):
        " Stops the plugin thread and cleans the plugin data "
        pluginID = None
        for identifier, descriptor in self.activePlugins.iteritems():
            if descriptor.getPluginName() == plugin.getName():
                self.disconnect(descriptor.plugin.getObject(),
                                SIGNAL("PathChanged"), self.__onPathChanged)
                pluginID = identifier
                descriptor.stopThread()
                self.fileCache.dismissPlugin(pluginID,
                                             self.sendFileStatusNotification)
                self.dirCache.dismissPlugin(pluginID,
                                            self.sendDirStatusNotification)

        if pluginID:
            del self.activePlugins[pluginID]

        if self.activePluginCount() == 0:
            self.__dirRequestLoopTimer.stop()
        return

    def requestStatus(self,
                      path,
                      flag=VersionControlSystemInterface.REQUEST_ITEM_ONLY):
        " Provides the path status asynchronously via sending a signal "
        delta = datetime.timedelta(0, Settings().vcsstatusupdateinterval)
        if path.endswith(os.path.sep):
            status = self.dirCache.getStatus(path)
            if status:
                self.sendDirStatusNotification(path, status)
            else:
                self.sendDirStatusNotification(path, VCSStatus())
        else:
            status = self.fileCache.getStatus(path)
            if status:
                self.sendFileStatusNotification(path, status)
            else:
                self.sendFileStatusNotification(path, VCSStatus())

        if status is None:
            for _, descriptor in self.activePlugins.iteritems():
                descriptor.requestStatus(path, flag, True)
        else:
            if status.indicatorID is None or \
               status.lastUpdate is None or \
               datetime.datetime.now() - status.lastUpdate > delta:
                # Outdated or never been received
                if status.pluginID in self.activePlugins:
                    # Path is claimed by a plugin
                    descriptor = self.activePlugins[status.pluginID]
                    descriptor.requestStatus(path, flag, True)
                    return
                # Path is not claimed by any plugin - send to all
                for _, descriptor in self.activePlugins.iteritems():
                    descriptor.requestStatus(path, flag, True)
        return

    def setLocallyModified(self, path):
        " Sets the item status as locally modified "
        for _, descriptor in self.activePlugins.iteritems():
            descriptor.requestStatus(
                path, VersionControlSystemInterface.REQUEST_ITEM_ONLY, True)
        return

    def sendDirStatusNotification(self, path, status):
        " Sends a signal that a status of the directory is changed "
        self.emit(SIGNAL("VCSDirStatus"), path, status)
        return

    def sendFileStatusNotification(self, path, status):
        " Sends a signal that a status of the file is changed "
        self.emit(SIGNAL("VCSFileStatus"), path, status)
        return

    def updateStatus(self, path, pluginID, indicatorID, message):
        " Called when a plugin thread reports a status "
        if path.endswith(os.path.sep):
            self.dirCache.updateStatus(path, pluginID, indicatorID, message,
                                       self.sendDirStatusNotification)
        else:
            self.fileCache.updateStatus(path, pluginID, indicatorID, message,
                                        self.sendFileStatusNotification)
        #print "Status of " + path + " is " + str( indicatorID ) + " Message: " + str( message ) + " Plugin ID: " + str( pluginID )
        return

    def activePluginCount(self):
        " Returns the number of active VCS plugins "
        return len(self.activePlugins)

    def drawStatus(self, vcsLabel, status):
        " Draw the VCS status "
        if status.pluginID not in self.activePlugins:
            vcsLabel.setVisible(False)
            return

        descriptor = self.activePlugins[status.pluginID]
        if status.indicatorID not in descriptor.indicators:
            # Check the standard indicator
            if status.indicatorID in self.systemIndicators:
                indicator = self.systemIndicators[status.indicatorID]
                indicator.draw(vcsLabel)
                if status.message:
                    vcsLabel.setToolTip(status.message)
                else:
                    vcsLabel.setToolTip(indicator.defaultTooltip)
            else:
                # Neither plugin, no standard indicator
                try:
                    indicator = self.systemIndicators[IND_VCS_ERROR]
                    indicator.draw(vcsLabel)
                    vcsLabel.setToolTip("VCS plugin provided undefined "
                                        "indicator (id is " +
                                        str(status.indicatorID) + ")")
                except:
                    # No way to display indicator
                    vcsLabel.setVisible(False)
            return

        indicator = descriptor.indicators[status.indicatorID]
        indicator.draw(vcsLabel)
        if status.message:
            vcsLabel.setToolTip(status.message)
        else:
            vcsLabel.setToolTip(indicator.defaultTooltip)
        return

    def getStatusIndicator(self, status):
        """ Provides the VCS status indicator description for the given status.
            It is mostly used for the project browser """
        if status.pluginID not in self.activePlugins:
            return None

        descriptor = self.activePlugins[status.pluginID]
        if status.indicatorID not in descriptor.indicators:
            # Check the standard indicator
            return self.getSystemIndicator(status.indicatorID)

        return descriptor.indicators[status.indicatorID]

    def getSystemIndicator(self, indicatorID):
        " Provides the IDE defined indicator if so "
        if indicatorID in self.systemIndicators:
            return self.systemIndicators[indicatorID]
        return None

    def __canInitiateStatusRequestLoop(self):
        " Returns true if the is no jam in the request queue "
        for _, descriptor in self.activePlugins.iteritems():
            if descriptor.canInitiateStatusRequestLoop():
                return True
        return False

    def __onDirRequestLoopTimer(self):
        " Triggered when the dir request loop timer is fired "
        self.__dirRequestLoopTimer.stop()
        if self.activePluginCount() == 0:
            return

        if self.__canInitiateStatusRequestLoop():
            self.__sendPeriodicDirectoryRequests()
        self.__startDirRequestTimer()
        return

    def __startDirRequestTimer(self):
        " Starts the periodic request timer "
        self.__dirRequestLoopTimer.start(Settings().vcsstatusupdateinterval *
                                         1000)
        return
示例#4
0
class VCSManager(QObject):
    """ Manages the VCS plugins.
        It sends two signals:
        VCSFileStatus -> path, pluginID, indicatorID, message
        VCSDirStatus -> path, pluginID, indicatorID, message
            The pluginID, indicatorID, message could be None
    """

    def __init__(self):
        QObject.__init__(self)

        self.dirCache = VCSStatusCache()  # Path -> VCSStatus
        self.fileCache = VCSStatusCache()  # Path -> VCSStatus
        self.activePlugins = {}  # Plugin ID -> VCSPluginDescriptor
        self.systemIndicators = {}  # ID -> VCSIndicator

        self.__firstFreeIndex = 0

        self.__readSettingsIndicators()
        self.__dirRequestLoopTimer = QTimer(self)
        self.__dirRequestLoopTimer.setSingleShot(True)
        self.__dirRequestLoopTimer.timeout.connect(self.__onDirRequestLoopTimer)

        GlobalData().project.projectChanged.connect(self.__onProjectChanged)
        GlobalData().project.fsChanged.connect(self.__onFSChanged)
        self.connect(GlobalData().pluginManager, SIGNAL("PluginActivated"), self.__onPluginActivated)

        # Plugin deactivation must be done via dismissPlugin(...)
        return

    def __getNewPluginIndex(self):
        " Provides a new plugin index "
        index = self.__firstFreeIndex
        self.__firstFreeIndex += 1
        return index

    def __readSettingsIndicators(self):
        " Reads the system indicators "
        for indicLine in Settings().vcsindicators:
            indicator = VCSIndicator(indicLine)
            self.systemIndicators[indicator.identifier] = indicator
        return

    def __onPluginActivated(self, plugin):
        " Triggered when a plugin is activated "
        if plugin.categoryName != "VersionControlSystemInterface":
            return

        newPluginIndex = self.__getNewPluginIndex()
        self.activePlugins[newPluginIndex] = VCSPluginDescriptor(self, newPluginIndex, plugin)
        self.connect(plugin.getObject(), SIGNAL("PathChanged"), self.__onPathChanged)

        # Need to send requests for the opened TAB files
        mainWindow = GlobalData().mainWindow
        editorsManager = mainWindow.editorsManagerWidget.editorsManager
        editorsManager.sendAllTabsVCSStatusRequest()

        if self.activePluginCount() == 1 and GlobalData().project.isLoaded():
            # This is the first plugin and a project is there
            self.__populateProjectDirectories()
        self.__sendDirectoryRequestsOnActivation(newPluginIndex)
        self.__sendFileRequestsOnActivation(newPluginIndex)

        if self.activePluginCount() == 1:
            self.__startDirRequestTimer()
        return

    def __onPathChanged(self, path):
        " The way plugins signal that a path has been changed "
        # What is essentially required is to update the status of the path.
        # setLocallyModified(...) will do - it sends urgent request
        self.setLocallyModified(path)

        # Changed paths may change the file contents
        mainWindow = GlobalData().mainWindow
        editorsManager = mainWindow.editorsManagerWidget.editorsManager
        editorsManager.checkOutsidePathChange(path)
        return

    def __populateProjectDirectories(self):
        " Populates the project directories in the dirCache "
        project = GlobalData().project
        for path in project.filesList:
            if path.endswith(os.path.sep):
                self.dirCache.updateStatus(path, None, None, None, None)
        return

    def __onProjectChanged(self, what):
        " Triggered when a project has changed "
        if what == CodimensionProject.CompleteProject:
            self.dirCache.clear()
            self.fileCache.clear()
            if len(self.activePlugins) == 0:
                return

            # There are some plugins
            for _, descriptor in self.activePlugins.iteritems():
                descriptor.clearRequestQueue()

            if GlobalData().project.isLoaded():
                self.__populateProjectDirectories()
            return

    def __onFSChanged(self, items):
        " Triggered when files/dirs in the project are changed "
        for item in items:
            item = str(item)
            if item.startswith("-"):
                item = item[1:]
                if item.endswith(os.path.sep):
                    # Directory removed
                    if item in self.dirCache.cache:
                        del self.dirCache.cache[item]
                else:
                    # File deleted
                    if item in self.fileCache.cache:
                        del self.fileCache.cache[item]
                    for _, descriptor in self.activePlugins.iteritems():
                        descriptor.requestStatus(item, VersionControlSystemInterface.REQUEST_ITEM_ONLY, True)
            else:
                item = item[1:]
                if item.endswith(os.path.sep):
                    # Directory added
                    if item not in self.dirCache.cache:
                        self.dirCache.updateStatus(item, None, None, None, None)
                    for _, descriptor in self.activePlugins.iteritems():
                        descriptor.requestStatus(item, VersionControlSystemInterface.REQUEST_DIRECTORY)
                else:
                    # File added
                    for _, descriptor in self.activePlugins.iteritems():
                        descriptor.requestStatus(item, VersionControlSystemInterface.REQUEST_ITEM_ONLY, True)
        return

    def __sendDirectoryRequestsOnActivation(self, pluginID):
        " Sends the directory requests to the given plugin "
        descriptor = self.activePlugins[pluginID]
        for path, status in self.dirCache.cache.iteritems():
            if status.indicatorID in [None, VersionControlSystemInterface.NOT_UNDER_VCS]:
                descriptor.requestStatus(path, VersionControlSystemInterface.REQUEST_DIRECTORY)
        return

    def __sendFileRequestsOnActivation(self, pluginID):
        " Sends the file requests to the given plugin "
        descriptor = self.activePlugins[pluginID]
        for path, status in self.fileCache.cache.iteritems():
            if status.indicatorID in [None, VersionControlSystemInterface.NOT_UNDER_VCS]:
                descriptor.requestStatus(path, VersionControlSystemInterface.REQUEST_ITEM_ONLY)
        return

    def __sendPeriodicDirectoryRequests(self):
        " Sends the directory requests periodically "
        for path, status in self.dirCache.cache.iteritems():
            if status.pluginID in self.activePlugins:
                # This directory is under certain VCS, send the request
                # only to this VCS
                descriptor = self.activePlugins[status.pluginID]
                descriptor.requestStatus(path, VersionControlSystemInterface.REQUEST_DIRECTORY)
            else:
                # The directory is not under any known VCS. Send the request
                # to all the registered VCS plugins
                for _, descriptor in self.activePlugins.iteritems():
                    descriptor.requestStatus(path, VersionControlSystemInterface.REQUEST_DIRECTORY)
        return

    def dismissAllPlugins(self):
        " Stops all the plugin threads "
        self.__dirRequestLoopTimer.stop()

        for identifier, descriptor in self.activePlugins.iteritems():
            self.disconnect(descriptor.plugin.getObject(), SIGNAL("PathChanged"), self.__onPathChanged)
            descriptor.stopThread()

        self.dirCache.clear()
        self.fileCache.clear()
        self.activePlugins = {}
        return

    def dismissPlugin(self, plugin):
        " Stops the plugin thread and cleans the plugin data "
        pluginID = None
        for identifier, descriptor in self.activePlugins.iteritems():
            if descriptor.getPluginName() == plugin.getName():
                self.disconnect(descriptor.plugin.getObject(), SIGNAL("PathChanged"), self.__onPathChanged)
                pluginID = identifier
                descriptor.stopThread()
                self.fileCache.dismissPlugin(pluginID, self.sendFileStatusNotification)
                self.dirCache.dismissPlugin(pluginID, self.sendDirStatusNotification)

        if pluginID:
            del self.activePlugins[pluginID]

        if self.activePluginCount() == 0:
            self.__dirRequestLoopTimer.stop()
        return

    def requestStatus(self, path, flag=VersionControlSystemInterface.REQUEST_ITEM_ONLY):
        " Provides the path status asynchronously via sending a signal "
        delta = datetime.timedelta(0, Settings().vcsstatusupdateinterval)
        if path.endswith(os.path.sep):
            status = self.dirCache.getStatus(path)
            if status:
                self.sendDirStatusNotification(path, status)
            else:
                self.sendDirStatusNotification(path, VCSStatus())
        else:
            status = self.fileCache.getStatus(path)
            if status:
                self.sendFileStatusNotification(path, status)
            else:
                self.sendFileStatusNotification(path, VCSStatus())

        if status is None:
            for _, descriptor in self.activePlugins.iteritems():
                descriptor.requestStatus(path, flag, True)
        else:
            if (
                status.indicatorID is None
                or status.lastUpdate is None
                or datetime.datetime.now() - status.lastUpdate > delta
            ):
                # Outdated or never been received
                if status.pluginID in self.activePlugins:
                    # Path is claimed by a plugin
                    descriptor = self.activePlugins[status.pluginID]
                    descriptor.requestStatus(path, flag, True)
                    return
                # Path is not claimed by any plugin - send to all
                for _, descriptor in self.activePlugins.iteritems():
                    descriptor.requestStatus(path, flag, True)
        return

    def setLocallyModified(self, path):
        " Sets the item status as locally modified "
        for _, descriptor in self.activePlugins.iteritems():
            descriptor.requestStatus(path, VersionControlSystemInterface.REQUEST_ITEM_ONLY, True)
        return

    def sendDirStatusNotification(self, path, status):
        " Sends a signal that a status of the directory is changed "
        self.emit(SIGNAL("VCSDirStatus"), path, status)
        return

    def sendFileStatusNotification(self, path, status):
        " Sends a signal that a status of the file is changed "
        self.emit(SIGNAL("VCSFileStatus"), path, status)
        return

    def updateStatus(self, path, pluginID, indicatorID, message):
        " Called when a plugin thread reports a status "
        if path.endswith(os.path.sep):
            self.dirCache.updateStatus(path, pluginID, indicatorID, message, self.sendDirStatusNotification)
        else:
            self.fileCache.updateStatus(path, pluginID, indicatorID, message, self.sendFileStatusNotification)
        # print "Status of " + path + " is " + str( indicatorID ) + " Message: " + str( message ) + " Plugin ID: " + str( pluginID )
        return

    def activePluginCount(self):
        " Returns the number of active VCS plugins "
        return len(self.activePlugins)

    def drawStatus(self, vcsLabel, status):
        " Draw the VCS status "
        if status.pluginID not in self.activePlugins:
            vcsLabel.setVisible(False)
            return

        descriptor = self.activePlugins[status.pluginID]
        if status.indicatorID not in descriptor.indicators:
            # Check the standard indicator
            if status.indicatorID in self.systemIndicators:
                indicator = self.systemIndicators[status.indicatorID]
                indicator.draw(vcsLabel)
                if status.message:
                    vcsLabel.setToolTip(status.message)
                else:
                    vcsLabel.setToolTip(indicator.defaultTooltip)
            else:
                # Neither plugin, no standard indicator
                try:
                    indicator = self.systemIndicators[IND_VCS_ERROR]
                    indicator.draw(vcsLabel)
                    vcsLabel.setToolTip(
                        "VCS plugin provided undefined " "indicator (id is " + str(status.indicatorID) + ")"
                    )
                except:
                    # No way to display indicator
                    vcsLabel.setVisible(False)
            return

        indicator = descriptor.indicators[status.indicatorID]
        indicator.draw(vcsLabel)
        if status.message:
            vcsLabel.setToolTip(status.message)
        else:
            vcsLabel.setToolTip(indicator.defaultTooltip)
        return

    def getStatusIndicator(self, status):
        """ Provides the VCS status indicator description for the given status.
            It is mostly used for the project browser """
        if status.pluginID not in self.activePlugins:
            return None

        descriptor = self.activePlugins[status.pluginID]
        if status.indicatorID not in descriptor.indicators:
            # Check the standard indicator
            return self.getSystemIndicator(status.indicatorID)

        return descriptor.indicators[status.indicatorID]

    def getSystemIndicator(self, indicatorID):
        " Provides the IDE defined indicator if so "
        if indicatorID in self.systemIndicators:
            return self.systemIndicators[indicatorID]
        return None

    def __canInitiateStatusRequestLoop(self):
        " Returns true if the is no jam in the request queue "
        for _, descriptor in self.activePlugins.iteritems():
            if descriptor.canInitiateStatusRequestLoop():
                return True
        return False

    def __onDirRequestLoopTimer(self):
        " Triggered when the dir request loop timer is fired "
        self.__dirRequestLoopTimer.stop()
        if self.activePluginCount() == 0:
            return

        if self.__canInitiateStatusRequestLoop():
            self.__sendPeriodicDirectoryRequests()
        self.__startDirRequestTimer()
        return

    def __startDirRequestTimer(self):
        " Starts the periodic request timer "
        self.__dirRequestLoopTimer.start(Settings().vcsstatusupdateinterval * 1000)
        return