Beispiel #1
0
    def __init__(self, application):
        QtCore.QObject.__init__(self)
        self.fileManager = application.fileManager
        self.supportManager = application.supportManager

        self.projectTreeModel = ProjectTreeModel(self)

        self.projectTreeProxyModel = ProjectTreeProxyModel(self)
        self.projectTreeProxyModel.setSourceModel(self.projectTreeModel)

        self.projectMenuProxyModel = ProjectMenuProxyModel(self)
        self.projectMenuProxyModel.setSourceModel(
            self.application.supportManager.bundleProxyModel)

        self.supportManager.bundleAdded.connect(
            self.on_supportManager_bundleAdded)
        self.supportManager.bundleRemoved.connect(
            self.on_supportManager_bundleRemoved)
Beispiel #2
0
    def __init__(self, application):
        QtCore.QObject.__init__(self)
        self.fileManager = application.fileManager
        self.supportManager = application.supportManager

        self.projectTreeModel = ProjectTreeModel(self)

        self.projectTreeProxyModel = ProjectTreeProxyModel(self)
        self.projectTreeProxyModel.setSourceModel(self.projectTreeModel)

        self.projectMenuProxyModel = ProjectMenuProxyModel(self)
        self.projectMenuProxyModel.setSourceModel(self.application.supportManager.bundleProxyModel)

        self.supportManager.bundleAdded.connect(self.on_supportManager_bundleAdded)
        self.supportManager.bundleRemoved.connect(self.on_supportManager_bundleRemoved)
Beispiel #3
0
    def __init__(self, **kwargs):
        super(ProjectManager, self).__init__(**kwargs)
        self.fileManager = self.application().fileManager
        self.supportManager = self.application().supportManager

        self.projectTreeModel = ProjectTreeModel(self)
        self.keywordsListModel = CheckableListModel(self)
        self.propertiesTreeModel = PropertiesTreeModel(parent=self)

        self.projectTreeProxyModel = ProjectTreeProxyModel(self)
        self.projectTreeProxyModel.setSourceModel(self.projectTreeModel)

        self.projectMenuProxyModel = ProjectMenuProxyModel(self)
        self.projectMenuProxyModel.setSourceModel(self.application().supportManager.bundleProxyModel)

        self.propertiesProxyModel = PropertiesProxyModel(parent = self)
        self.propertiesProxyModel.setSourceModel(self.propertiesTreeModel)

        self.supportManager.bundleAdded.connect(self.on_supportManager_bundleAdded)
        self.supportManager.bundleRemoved.connect(self.on_supportManager_bundleRemoved)
        self.supportManager.bundleItemAdded.connect(self.on_supportManager_bundleItemAdded)
        self.supportManager.bundleItemRemoved.connect(self.on_supportManager_bundleItemRemoved)
        self.message_handler = None
Beispiel #4
0
class ProjectManager(QtCore.QObject, PMXBaseComponent):
    #Signals
    projectAdded = QtCore.pyqtSignal(object)
    projectRemoved = QtCore.pyqtSignal(object)
    projectClose = QtCore.pyqtSignal(object)
    projectOpen = QtCore.pyqtSignal(object)
    
    #Settings
    SETTINGS_GROUP = 'ProjectManager'
    
    workspaceDirectory  = pmxConfigPorperty(default = os.path.join(get_home_dir(), "workspace"))  #Eclipse muejejeje
    knownProjects = pmxConfigPorperty(default = [])
    workingSets = pmxConfigPorperty(default = {})
    
    VALID_PATH_CARACTERS = "-_.() %s%s" % (string.ascii_letters, string.digits)
    
    def __init__(self, application):
        QtCore.QObject.__init__(self)
        self.fileManager = application.fileManager
        self.supportManager = application.supportManager

        self.projectTreeModel = ProjectTreeModel(self)

        self.projectTreeProxyModel = ProjectTreeProxyModel(self)
        self.projectTreeProxyModel.setSourceModel(self.projectTreeModel)

        self.projectMenuProxyModel = ProjectMenuProxyModel(self)
        self.projectMenuProxyModel.setSourceModel(self.application.supportManager.bundleProxyModel)

        self.supportManager.bundleAdded.connect(self.on_supportManager_bundleAdded)
        self.supportManager.bundleRemoved.connect(self.on_supportManager_bundleRemoved)

    @classmethod
    def contributeToSettings(cls):
        return []

    def convertToValidPath(self, name):
        #TODO: este y el del manager de bundles pasarlos a utils
        validPath = []
        for char in unicodedata.normalize('NFKD', unicode(name)).encode('ASCII', 'ignore'):
            char = char if char in self.VALID_PATH_CARACTERS else '-'
            validPath.append(char)
        return ''.join(validPath)

    def on_supportManager_bundleAdded(self, bundle):
        for project in self.getAllProjects():
            if project.namespace is not None and bundle.hasNamespace(project.namespace) and not project.hasBundleMenu(bundle):
                self.addProjectBundleMenu(project, bundle)

    def on_supportManager_bundleRemoved(self, bundle):
        for project in self.getAllProjects():
            if project.namespace is not None and bundle.hasNamespace(project.namespace) and project.hasBundleMenu(bundle):
                self.removeProjectBundleMenu(project, bundle)

    def loadProjects(self):
        for path in self.knownProjects[:]:
            try:
                ProjectTreeNode.loadProject(path, self)
            except exceptions.FileNotExistsException as e:
                print e
                self.knownProjects.remove(path)
                self.settings.setValue('knownProjects', self.knownProjects)

    def isOpen(self, project):
        return True

    def appendToKnowProjects(self, project):
        self.knownProjects.append(project.path())
        self.settings.setValue('knownProjects', self.knownProjects)

    def removeFromKnowProjects(self, project):
        self.knownProjects.remove(project.path())
        self.settings.setValue('knownProjects', self.knownProjects)
    
    #---------------------------------------------------
    # Environment
    #---------------------------------------------------
    def environmentVariables(self):
        return {}
    
    def supportProjectEnvironment(self, project):
        return self.supportManager.projectEnvironment(project)

    #---------------------------------------------------
    # PROJECT CRUD
    #---------------------------------------------------
    def createProject(self, name, directory, description = None, reuseDirectory = True):
        """
        Crea un proyecto nuevo lo agrega en los existentes y lo retorna,
        """
        #TODO: dejar este trabajo al file manager
        if not os.path.exists(directory):
            os.makedirs(directory)
        elif not reuseDirectory:
            raise Exception()
        project = ProjectTreeNode(directory, { "name": name, "description": description })
        try:
            project.save()
        except ProjectExistsException:
            rslt = QtGui.QMessageBox.information(None, _("Project already created on %s") % name,
                                          _("Directory %s already contains .pmxproject directory structure. "
                                            "Unless you know what you are doing, Cancel and import project,"
                                            " if it still fails, choose overwirte. Overwrite?") % directory,
                                          QtGui.QMessageBox.Cancel | QtGui.QMessageBox.Ok, QtGui.QMessageBox.Cancel) 
            if rslt == QtGui.QMessageBox.Cancel:
                return
            try:
                project.save(overwirte = True)
            except FileException as excp:
                QtGui.QMessageBox.critical(None, _("Project creation failed"), 
                                           _("<p>Project %s could not be created<p><pre>%s</pre>") % (name, excp))
        self.addProject(project)
        self.appendToKnowProjects(project)
        return project
    
    def updateProject(self, project, **attrs):
        """Actualiza un proyecto"""
        if len(attrs) == 1 and "name" in attrs and attrs["name"] == item.name:
            #Updates que no son updates
            return item

        project.update(attrs)
        project.save()
        return project

    def importProject(self, directory):
        try:
            project = ProjectTreeNode.loadProject(directory, self)
        except exceptions.FileNotExistsException:
            raise exceptions.LocationIsNotProject()
        self.appendToKnowProjects(project)

    def deleteProject(self, project, removeFiles = False):
        """
        Elimina un proyecto
        """
        project.delete(removeFiles)
        self.removeProject(project)

    #---------------------------------------------------
    # PROJECT INTERFACE
    #---------------------------------------------------
    def addProject(self, project):
        project.setManager(self)
        # Todo proyecto define un namespace en el manager de support
        self.application.supportManager.addProjectNamespace(project)
        self.projectTreeModel.appendProject(project)
        self.projectAdded.emit(project)

    def modifyProject(self, project):
        pass

    def removeProject(self, project):
        self.removeFromKnowProjects(project)
        self.projectTreeModel.removeProject(project)

    def getAllProjects(self):
        #TODO: devolver un copia o no hace falta?
        return self.projectTreeModel.rootNode.childNodes()

    def openProject(self, project):
        # Cuando abro un proyecto agrego su namespace al support para aportar bundles y themes
        print project.directory

    def closeProject(self, project):
        # Cuando cierro un proyecto quito su namespace al support
        print project.directory

    def setWorkingSet(self, project, workingSet):
        projects = self.workingSets.setdefault(workingSet)
        projects.append(project.filePath)
        project.setWorkingSet(workingSet)
        self.projectTreeModel.dataChanged.emit()

    def addProjectBundleMenu(self, project, bundle):
        project.addBundleMenu(bundle)
        project.save()

    def removeProjectBundleMenu(self, project, bundle):
        project.removeBundleMenu(bundle)
        project.save()

    def findProjectForPath(self, path):
        for project in self.getAllProjects():
            if self.application.fileManager.issubpath(path, project.path()):
                return project
Beispiel #5
0
class ProjectManager(PrymatexComponent, QtCore.QObject):
    #Signals
    projectAdded = QtCore.Signal(object)
    projectRemoved = QtCore.Signal(object)
    projectClose = QtCore.Signal(object)
    projectOpen = QtCore.Signal(object)

    # ------------- Settings
    default_directory  = ConfigurableItem(
        default=os.path.join(config.USER_HOME_PATH, "Projects")
    )

    VALID_PATH_CARACTERS = "-_.() %s%s" % (string.ascii_letters, string.digits)

    def __init__(self, **kwargs):
        super(ProjectManager, self).__init__(**kwargs)
        self.fileManager = self.application().fileManager
        self.supportManager = self.application().supportManager

        self.projectTreeModel = ProjectTreeModel(self)
        self.keywordsListModel = CheckableListModel(self)
        self.propertiesTreeModel = PropertiesTreeModel(parent=self)

        self.projectTreeProxyModel = ProjectTreeProxyModel(self)
        self.projectTreeProxyModel.setSourceModel(self.projectTreeModel)

        self.projectMenuProxyModel = ProjectMenuProxyModel(self)
        self.projectMenuProxyModel.setSourceModel(self.application().supportManager.bundleProxyModel)

        self.propertiesProxyModel = PropertiesProxyModel(parent = self)
        self.propertiesProxyModel.setSourceModel(self.propertiesTreeModel)

        self.supportManager.bundleAdded.connect(self.on_supportManager_bundleAdded)
        self.supportManager.bundleRemoved.connect(self.on_supportManager_bundleRemoved)
        self.supportManager.bundleItemAdded.connect(self.on_supportManager_bundleItemAdded)
        self.supportManager.bundleItemRemoved.connect(self.on_supportManager_bundleItemRemoved)
        self.message_handler = None
    
    # ---------- OVERRIDE: PrymatexComponent.contributeToSettings()
    @classmethod
    def contributeToSettings(cls):
        from prymatex.gui.settings.projects import ProjectSettingsWidget
        from prymatex.gui.settings.addons import AddonsSettingsWidgetFactory
        return [ ProjectSettingsWidget, AddonsSettingsWidgetFactory("projects") ]

    # ---------- OVERRIDE: PrymatexComponent.componentState()
    def componentState(self):
        componentState = super(ProjectManager, self).componentState()

        componentState["projects"] = []
        for project in self.projectTreeModel.projects():
            componentState["projects"].append(project.path())

        return componentState

    # ---------- OVERRIDE: PrymatexComponent.setComponentState()
    def setComponentState(self, componentState):
        super(ProjectManager, self).setComponentState(componentState)
        
        # Restore projects
        for project_path in componentState.get("projects", []):
            try:
                self.openProject(project_path)
            except exceptions.FileIsNotProject as ex:
                pass
        
    def setupPropertiesWidgets(self):
        from prymatex.gui.properties.project import ProjectPropertiesWidget
        from prymatex.gui.properties.environment import EnvironmentPropertiesWidget
        from prymatex.gui.properties.resource import ResoucePropertiesWidget
        
        for property_class in [ProjectPropertiesWidget, EnvironmentPropertiesWidget, ResoucePropertiesWidget]:
            property_class.application = self.application
            self.registerPropertyWidget(property_class())

    def convertToValidPath(self, name):
        #TODO: este y el del manager de bundles pasarlos a utils
        validPath = []
        for char in unicodedata.normalize('NFKD', str(name)).encode('ASCII', 'ignore'):
            char = char if char in self.VALID_PATH_CARACTERS else '-'
            validPath.append(char)
        return ''.join(validPath)

    # -------------- Signals from suppor manager
    def on_supportManager_bundleAdded(self, bundle):
        for project in self.getAllProjects():
            if bundle.hasSource(project.namespaceName) and not project.hasBundleMenu(bundle):
                self.addProjectBundleMenu(project, bundle)

    def on_supportManager_bundleRemoved(self, bundle):
        for project in self.getAllProjects():
            if bundle.hasSource(project.namespaceName) and project.hasBundleMenu(bundle):
                self.removeProjectBundleMenu(project, bundle)

    def on_supportManager_bundleItemAdded(self, node):
        item = node.bundleItem()
        if item.type() == "syntax":
            self.keywordsListModel.addItems(item.scopeName.split('.'))

    def on_supportManager_bundleItemRemoved(self, node):
        item = node.bundleItem()
        if item.type() == "syntax":
            self.keywordsListModel.removeItems(item.scopeName.split('.'))

    # -------------------- Load projects
    def loadProjects(self, message_handler=None, *args, **kwargs):
        self.message_handler = message_handler
        self.setupPropertiesWidgets()
        self.message_handler = None

    def isOpen(self, project):
        return True

    # ------------------- Properties
    def registerPropertyWidget(self, propertyWidget):
        self.propertiesTreeModel.addConfigNode(propertyWidget)

    #---------------------------------------------------
    # Environment
    #---------------------------------------------------
    def environmentVariables(self):
        return {}

    #---------------------------------------------------
    # PROJECT CRUD
    #---------------------------------------------------
    def createProject(self, name, file_path, folders=(), overwrite=False):
        """Crea un proyecto nuevo y lo retorna"""
        if not overwrite and os.path.exists(file_path):
            raise exceptions.ProjectExistsException()

        project = ProjectTreeNode(name, file_path)
        project.load({
            "name": name,
            "source_folders": folders 
        })
        project.save()

        self.addProject(project)
        return project

    def updateProject(self, project, **attrs):
        """Actualiza un proyecto"""
        project.update(attrs)
        project.save()
        return project

    def openProject(self, file_path):
        try:
            project = ProjectTreeNode.loadProject(file_path, self)
        except exceptions.FileNotExistsException:
            raise exceptions.FileIsNotProject()

    def deleteProject(self, project, removeFiles = False):
        """Elimina un proyecto"""
        project.delete(removeFiles)
        self.removeProject(project)

    # ---------------- Project sources
    def addSourceFolder(self, project, path):
        project.addSourceFolder(path)
        project.save()
        
    def removeSourceFolder(self, project, path):
        project.removeSourceFolder(path)
        project.save()
        
    # ---------------- Project namespaces
    def addNamespaceFolder(self, project, path):
        namespace = self.application().createNamespace(project.nodeName(), path)
        self.application().addNamespace(namespace)
        project.addNamespace(namespace)
        project.save()
        
    def removeNamespace(self, project, namespace):
        project.removeNamespace(namespace)
        project.save()
        
    # ----------------------- PROJECT INTERFACE
    def addProject(self, project):
        project.setManager(self)
        # Agregar los namespace folders
        for folder in project.namespace_folders:
            self.addNamespaceFolder(project, folder)
        self.projectTreeModel.appendProject(project)
        self.projectAdded.emit(project)

    def modifyProject(self, project):
        pass

    def removeProject(self, project):
        self.projectTreeModel.removeProject(project)

    def getAllProjects(self):
        #TODO: devolver un copia o no hace falta?
        return self.projectTreeModel.rootNode.children()

    def closeProject(self, project):
        # Cuando cierro un proyecto quito su namespace al support
        print(project.path())

    def addProjectBundleMenu(self, project, bundle):
        project.addBundleMenu(bundle)
        project.save()

    def removeProjectBundleMenu(self, project, bundle):
        project.removeBundleMenu(bundle)
        project.save()

    def findProjectForPath(self, path):
        file_manager = self.application().fileManager
        for project in self.getAllProjects():
            if any(file_manager.issubpath(path, source) for source in project.source_folders):
                return project
Beispiel #6
0
class ProjectManager(QtCore.QObject, PMXBaseComponent):
    #Signals
    projectAdded = QtCore.pyqtSignal(object)
    projectRemoved = QtCore.pyqtSignal(object)
    projectClose = QtCore.pyqtSignal(object)
    projectOpen = QtCore.pyqtSignal(object)

    #Settings
    SETTINGS_GROUP = 'ProjectManager'

    workspaceDirectory = pmxConfigPorperty(default=os.path.join(
        get_home_dir(), "workspace"))  #Eclipse muejejeje
    knownProjects = pmxConfigPorperty(default=[])
    workingSets = pmxConfigPorperty(default={})

    VALID_PATH_CARACTERS = "-_.() %s%s" % (string.ascii_letters, string.digits)

    def __init__(self, application):
        QtCore.QObject.__init__(self)
        self.fileManager = application.fileManager
        self.supportManager = application.supportManager

        self.projectTreeModel = ProjectTreeModel(self)

        self.projectTreeProxyModel = ProjectTreeProxyModel(self)
        self.projectTreeProxyModel.setSourceModel(self.projectTreeModel)

        self.projectMenuProxyModel = ProjectMenuProxyModel(self)
        self.projectMenuProxyModel.setSourceModel(
            self.application.supportManager.bundleProxyModel)

        self.supportManager.bundleAdded.connect(
            self.on_supportManager_bundleAdded)
        self.supportManager.bundleRemoved.connect(
            self.on_supportManager_bundleRemoved)

    @classmethod
    def contributeToSettings(cls):
        return []

    def convertToValidPath(self, name):
        #TODO: este y el del manager de bundles pasarlos a utils
        validPath = []
        for char in unicodedata.normalize('NFKD', unicode(name)).encode(
                'ASCII', 'ignore'):
            char = char if char in self.VALID_PATH_CARACTERS else '-'
            validPath.append(char)
        return ''.join(validPath)

    def on_supportManager_bundleAdded(self, bundle):
        for project in self.getAllProjects():
            if project.namespace is not None and bundle.hasNamespace(
                    project.namespace) and not project.hasBundleMenu(bundle):
                self.addProjectBundleMenu(project, bundle)

    def on_supportManager_bundleRemoved(self, bundle):
        for project in self.getAllProjects():
            if project.namespace is not None and bundle.hasNamespace(
                    project.namespace) and project.hasBundleMenu(bundle):
                self.removeProjectBundleMenu(project, bundle)

    def loadProjects(self):
        for path in self.knownProjects[:]:
            try:
                ProjectTreeNode.loadProject(path, self)
            except exceptions.FileNotExistsException as e:
                print e
                self.knownProjects.remove(path)
                self.settings.setValue('knownProjects', self.knownProjects)

    def isOpen(self, project):
        return True

    def appendToKnowProjects(self, project):
        self.knownProjects.append(project.path())
        self.settings.setValue('knownProjects', self.knownProjects)

    def removeFromKnowProjects(self, project):
        self.knownProjects.remove(project.path())
        self.settings.setValue('knownProjects', self.knownProjects)

    #---------------------------------------------------
    # Environment
    #---------------------------------------------------
    def environmentVariables(self):
        return {}

    def supportProjectEnvironment(self, project):
        return self.supportManager.projectEnvironment(project)

    #---------------------------------------------------
    # PROJECT CRUD
    #---------------------------------------------------
    def createProject(self,
                      name,
                      directory,
                      description=None,
                      reuseDirectory=True):
        """
        Crea un proyecto nuevo lo agrega en los existentes y lo retorna,
        """
        #TODO: dejar este trabajo al file manager
        if not os.path.exists(directory):
            os.makedirs(directory)
        elif not reuseDirectory:
            raise Exception()
        project = ProjectTreeNode(directory, {
            "name": name,
            "description": description
        })
        try:
            project.save()
        except ProjectExistsException:
            rslt = QtGui.QMessageBox.information(
                None,
                _("Project already created on %s") % name,
                _("Directory %s already contains .pmxproject directory structure. "
                  "Unless you know what you are doing, Cancel and import project,"
                  " if it still fails, choose overwirte. Overwrite?") %
                directory, QtGui.QMessageBox.Cancel | QtGui.QMessageBox.Ok,
                QtGui.QMessageBox.Cancel)
            if rslt == QtGui.QMessageBox.Cancel:
                return
            try:
                project.save(overwirte=True)
            except FileException as excp:
                QtGui.QMessageBox.critical(
                    None, _("Project creation failed"),
                    _("<p>Project %s could not be created<p><pre>%s</pre>") %
                    (name, excp))
        self.addProject(project)
        self.appendToKnowProjects(project)
        return project

    def updateProject(self, project, **attrs):
        """Actualiza un proyecto"""
        if len(attrs) == 1 and "name" in attrs and attrs["name"] == item.name:
            #Updates que no son updates
            return item

        project.update(attrs)
        project.save()
        return project

    def importProject(self, directory):
        try:
            project = ProjectTreeNode.loadProject(directory, self)
        except exceptions.FileNotExistsException:
            raise exceptions.LocationIsNotProject()
        self.appendToKnowProjects(project)

    def deleteProject(self, project, removeFiles=False):
        """
        Elimina un proyecto
        """
        project.delete(removeFiles)
        self.removeProject(project)

    #---------------------------------------------------
    # PROJECT INTERFACE
    #---------------------------------------------------
    def addProject(self, project):
        project.setManager(self)
        # Todo proyecto define un namespace en el manager de support
        self.application.supportManager.addProjectNamespace(project)
        self.projectTreeModel.appendProject(project)
        self.projectAdded.emit(project)

    def modifyProject(self, project):
        pass

    def removeProject(self, project):
        self.removeFromKnowProjects(project)
        self.projectTreeModel.removeProject(project)

    def getAllProjects(self):
        #TODO: devolver un copia o no hace falta?
        return self.projectTreeModel.rootNode.childNodes()

    def openProject(self, project):
        # Cuando abro un proyecto agrego su namespace al support para aportar bundles y themes
        print project.directory

    def closeProject(self, project):
        # Cuando cierro un proyecto quito su namespace al support
        print project.directory

    def setWorkingSet(self, project, workingSet):
        projects = self.workingSets.setdefault(workingSet)
        projects.append(project.filePath)
        project.setWorkingSet(workingSet)
        self.projectTreeModel.dataChanged.emit()

    def addProjectBundleMenu(self, project, bundle):
        project.addBundleMenu(bundle)
        project.save()

    def removeProjectBundleMenu(self, project, bundle):
        project.removeBundleMenu(bundle)
        project.save()

    def findProjectForPath(self, path):
        for project in self.getAllProjects():
            if self.application.fileManager.issubpath(path, project.path()):
                return project
Beispiel #7
0
class ProjectManager(PrymatexComponent, QtCore.QObject):
    #Signals
    projectAdded = QtCore.Signal(object)
    projectRemoved = QtCore.Signal(object)
    projectClose = QtCore.Signal(object)
    projectOpen = QtCore.Signal(object)

    #Settings
    SETTINGS_GROUP = 'ProjectManager'

    defaultDirectory  = ConfigurableItem(default = os.path.join(get_home_dir(), "projects"))
    knownProjects = ConfigurableItem(default = [])

    VALID_PATH_CARACTERS = "-_.() %s%s" % (string.ascii_letters, string.digits)

    def __init__(self, **kwargs):
        super(ProjectManager, self).__init__(**kwargs)
        self.fileManager = self.application.fileManager
        self.supportManager = self.application.supportManager

        self.projectTreeModel = ProjectTreeModel(self)
        self.keywordsListModel = CheckableListModel(self)
        self.propertiesTreeModel = PropertiesTreeModel(parent = self)

        self.projectTreeProxyModel = ProjectTreeProxyModel(self)
        self.projectTreeProxyModel.setSourceModel(self.projectTreeModel)

        self.projectMenuProxyModel = ProjectMenuProxyModel(self)
        self.projectMenuProxyModel.setSourceModel(self.application.supportManager.bundleProxyModel)

        self.propertiesProxyModel = PropertiesProxyModel(parent = self)
        self.propertiesProxyModel.setSourceModel(self.propertiesTreeModel)

        self.supportManager.bundleAdded.connect(self.on_supportManager_bundleAdded)
        self.supportManager.bundleRemoved.connect(self.on_supportManager_bundleRemoved)
        self.supportManager.bundleItemAdded.connect(self.on_supportManager_bundleItemAdded)
        self.supportManager.bundleItemRemoved.connect(self.on_supportManager_bundleItemRemoved)
        
        self.messageHandler = None
    
    @classmethod
    def contributeToSettings(cls):
        from prymatex.gui.settings.projects import ProjectSettingsWidget
        from prymatex.gui.settings.addons import AddonsSettingsWidgetFactory
        return [ ProjectSettingsWidget, AddonsSettingsWidgetFactory("general.projects") ]

    def convertToValidPath(self, name):
        #TODO: este y el del manager de bundles pasarlos a utils
        validPath = []
        for char in unicodedata.normalize('NFKD', str(name)).encode('ASCII', 'ignore'):
            char = char if char in self.VALID_PATH_CARACTERS else '-'
            validPath.append(char)
        return ''.join(validPath)

    # -------------- Signals from suppor manager
    def on_supportManager_bundleAdded(self, bundle):
        for project in self.getAllProjects():
            if bundle.hasSource(project.namespaceName) and not project.hasBundleMenu(bundle):
                self.addProjectBundleMenu(project, bundle)

    def on_supportManager_bundleRemoved(self, bundle):
        for project in self.getAllProjects():
            if bundle.hasSource(project.namespaceName) and project.hasBundleMenu(bundle):
                self.removeProjectBundleMenu(project, bundle)

    def on_supportManager_bundleItemAdded(self, bundleItem):
        if bundleItem.type() == "syntax":
            self.keywordsListModel.addItems(bundleItem.scopeName.split('.'))


    def on_supportManager_bundleItemRemoved(self, bundleItem):
        if bundleItem.type() == "syntax":
            self.keywordsListModel.removeItems(bundleItem.scopeName.split('.'))

    # -------------------- Load projects
    def loadProjects(self, messageHandler = None):
        self.messageHandler = messageHandler
        for path in self.knownProjects[:]:
            try:
                ProjectTreeNode.loadProject(path, self)
            except exceptions.FileNotExistsException as e:
                print(e)
                self.knownProjects.remove(path)
                self._settings.setValue('knownProjects', self.knownProjects)
        self.messageHandler = None

    def isOpen(self, project):
        return True

    def appendToKnowProjects(self, project):
        self.knownProjects.append(project.path())
        self._settings.setValue('knownProjects', self.knownProjects)

    def removeFromKnowProjects(self, project):
        self.knownProjects.remove(project.path())
        self._settings.setValue('knownProjects', self.knownProjects)

    # ------------------- Properties
    def registerPropertyWidget(self, propertyWidget):
        self.propertiesTreeModel.addConfigNode(propertyWidget)

    #---------------------------------------------------
    # Environment
    #---------------------------------------------------
    def environmentVariables(self):
        return {}

    #---------------------------------------------------
    # PROJECT CRUD
    #---------------------------------------------------
    def createProject(self, name, directory, overwrite = False):
        """Crea un proyecto nuevo y lo retorna"""
        project = ProjectTreeNode(directory, { "name": name })
        if not overwrite and os.path.exists(project.projectPath):
            raise exceptions.ProjectExistsException()

        project.save()
        self.addProject(project)
        self.appendToKnowProjects(project)
        return project

    def updateProject(self, project, **attrs):
        """Actualiza un proyecto"""
        project.update(attrs)
        project.save()
        return project

    def importProject(self, directory):
        try:
            project = ProjectTreeNode.loadProject(directory, self)
        except exceptions.FileNotExistsException:
            raise exceptions.LocationIsNotProject()
        self.appendToKnowProjects(project)

    def deleteProject(self, project, removeFiles = False):
        """Elimina un proyecto"""
        project.delete(removeFiles)
        self.removeProject(project)

    #---------------------------------------------------
    # PROJECT INTERFACE
    #---------------------------------------------------
    def addProject(self, project):
        project.setManager(self)
        # Todo proyecto define un namespace en el manager de support
        self.application.supportManager.addProjectNamespace(project)
        self.projectTreeModel.appendProject(project)
        self.projectAdded.emit(project)

    def modifyProject(self, project):
        pass

    def removeProject(self, project):
        self.removeFromKnowProjects(project)
        self.projectTreeModel.removeProject(project)

    def getAllProjects(self):
        #TODO: devolver un copia o no hace falta?
        return self.projectTreeModel.rootNode.childNodes()

    def openProject(self, project):
        # Cuando abro un proyecto agrego su namespace al support para aportar bundles y themes
        print(project.directory)

    def closeProject(self, project):
        # Cuando cierro un proyecto quito su namespace al support
        print(project.directory)

    def addProjectBundleMenu(self, project, bundle):
        project.addBundleMenu(bundle)
        project.save()

    def removeProjectBundleMenu(self, project, bundle):
        project.removeBundleMenu(bundle)
        project.save()

    def findProjectForPath(self, path):
        for project in self.getAllProjects():
            if self.application.fileManager.issubpath(path, project.path()):
                return project