예제 #1
0
class MainWindowModel(AbstractMainWindowModel):

    def __init__(self, mainWindow, repo, user, guiUpdater):
        self._repo = repo
        self._user = user
        self._mainWindow = mainWindow

        self.__actionHandlers = ActionHandlerStorage(guiUpdater)

        self.__favoriteReposStorage = FavoriteReposStorage()

        self._tools = []
        for tool in self.__getAvailableTools():
            self.__initTool(tool)


    def __getGui(self):
        return self._mainWindow
    gui = property(fget=__getGui)


    def __getAvailableTools(self):
        # TODO: Discovering of tools should be dynamic, like plugin system
        return [ItemsTable(self._mainWindow.widgetsUpdateManager(),
                           self._mainWindow,
                           self._mainWindow.dialogsFacade()),
                TagCloud(),
                FileBrowser(self._mainWindow.widgetsUpdateManager(),
                            self._mainWindow.dialogsFacade())]


    def __initTool(self, aTool):
        self._tools.append(aTool)

        self._mainWindow.initDockWidgetForTool(aTool)

        toolMainMenu = aTool.buildGuiMainMenu()
        if toolMainMenu is not None:
            self._mainWindow.addToolMainMenu(aTool.gui.mainMenu)

        self.__findAndConnectRelatedToolsFor(aTool)

        self._mainWindow.subscribeToolForUpdates(aTool)


    def __findAndConnectRelatedToolsFor(self, aTool):
        assert aTool is not None

        for relatedToolId in aTool.relatedToolIds():
            relatedTool = self.toolById(relatedToolId)
            if relatedTool is None:
                continue
            aTool.connectRelatedTool(relatedTool)


    def tools(self):
        return self._tools


    def toolById(self, toolId):
        foundTools = [tool for tool in self._tools if tool.id() == toolId]

        if len(foundTools) == 0:
            return None

        assert len(foundTools) == 1, "Tool id=%s is not unique!" % str(toolId)
        return foundTools[0]


    def __get_repo(self):
        return self._repo

    def __set_repo(self, repo):
        self._repo = repo
        self._mainWindow.onCurrentRepoChanged()
        for tool in self._tools:
            tool.setRepo(repo)

    repo = property(fget=__get_repo, fset=__set_repo)


    def __get_user(self):
        return self._user

    def __set_user(self, user):
        self._user = user
        self._mainWindow.onCurrentUserChanged()
        for tool in self._tools:
            tool.setUser(user)

    user = property(fget=__get_user, fset=__set_user)


    def loginRecentUser(self):
        login = UserConfig().get("recent_user.login")
        password = UserConfig().get("recent_user.password")
        self.loginUser(login, password)


    def loginUser(self, login, password):
        self.checkActiveRepoIsNotNone()

        uow = self._repo.createUnitOfWork()
        try:
            user = uow.executeCommand(LoginUserCommand(login, password))
            self.user = user
        finally:
            uow.close()


    def checkActiveRepoIsNotNone(self):
        if self._repo is None:
            raise CurrentRepoIsNoneError("Current repository is None")


    def checkActiveUserIsNotNone(self):
        if self._user is None:
            raise CurrentUserIsNoneError("Current user is None")


    def storeCurrentState(self):
        for tool in self._tools:
            tool.storeCurrentState()


    def restoreRecentState(self):
        #TODO: here we should restore recent user and recent repo. It is done in MainWindow now...
        for tool in self._tools:
            tool.restoreRecentState()


    def favoriteRepos(self, login):
        return self.__favoriteReposStorage.favoriteRepos(login)


    def connectOpenFavoriteRepoAction(self, action):
        actionHandler = handlers.OpenFavoriteRepoActionHandler(self)
        self.__actionHandlers.register(action, actionHandler)


    def disconnectOpenFavoriteRepoAction(self, action):
        self.__actionHandlers.unregister(action)


    def connectMenuActionsWithHandlers(self):
        ui = self._mainWindow.ui

        def initRepositoryMenu():
            self.__actionHandlers.register(
                ui.action_repo_create, handlers.CreateRepoActionHandler(self))

            self.__actionHandlers.register(
                ui.action_repo_close, handlers.CloseRepoActionHandler(self))

            self.__actionHandlers.register(
                ui.action_repo_open, handlers.OpenRepoActionHandler(self))

            self.__actionHandlers.register(
                ui.actionAdd_current_repository,
                handlers.AddCurrentRepoToFavoritesActionHandler(self, self.__favoriteReposStorage))

            self.__actionHandlers.register(
                ui.actionRemove_current_repository,
                handlers.RemoveCurrentRepoFromFavoritesActionHandler(self, self.__favoriteReposStorage))

            self.__actionHandlers.register(
                ui.actionImportItems, handlers.ImportItemsActionHandler(self, self._mainWindow.dialogsFacade()))

            self.__actionHandlers.register(
                ui.actionManageExtApps, handlers.ManageExternalAppsActionHandler(self, self._mainWindow.dialogsFacade()))

            self.__actionHandlers.register(
                ui.actionExitReggata, handlers.ExitReggataActionHandler(self))

        def initUserMenu():
            self.__actionHandlers.register(
                ui.action_user_create, handlers.CreateUserActionHandler(self))

            self.__actionHandlers.register(
                ui.action_user_login, handlers.LoginUserActionHandler(self))

            self.__actionHandlers.register(
                ui.action_user_logout, handlers.LogoutUserActionHandler(self))

            self.__actionHandlers.register(
                ui.action_user_change_pass, handlers.ChangeUserPasswordActionHandler(self))

        def initHelpMenu():
            self.__actionHandlers.register(
                ui.action_help_about, handlers.ShowAboutDialogActionHandler(self))

        initRepositoryMenu()
        initUserMenu()
        initHelpMenu()
예제 #2
0
class FileBrowser(AbstractTool):

    TOOL_ID = "FileBrowserTool"

    def __init__(self, guiUpdater, dialogsFacade):
        super(FileBrowser, self).__init__()
        self._guiUpdater = guiUpdater
        self._actionHandlers = None
        self._dialogsFacade = dialogsFacade
        self.__dropFilesDialogs = DropFilesDialogsFacade(dialogsFacade)
        self._gui = None
        self._repo = None
        self._user = None
        self._currDir = None
        self._listCache = None
        self._mutex = None
        self._thread = None
        self._enabled = False
        self._extAppMgr = ExtAppMgr()

        self._guiUpdater.subscribe(
            self._extAppMgr, self._extAppMgr.updateState,
            [HandlerSignals.REGGATA_CONF_CHANGED])

        logger.debug("File Browser __init__ finished.")


    def id(self):
        return self.TOOL_ID

    def title(self):
        return self.tr("File Browser")

    def createGui(self, guiParent):
        self._gui = FileBrowserGui(guiParent, self)
        self._actionHandlers = ActionHandlerStorage(self._guiUpdater)
        logger.debug("File Browser GUI created.")
        return self._gui

    def __getGui(self):
        return self._gui
    gui = property(fget=__getGui)


    def connectActionsWithActionHandlers(self):
        assert len(self._gui.actions) > 0, "Actions should be already built in ToolGui"

        self._actionHandlers.register(
            self._gui.actions['editItems'],
            EditItemsActionHandlerFileBrowser(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['addFiles'],
            AddFilesToRepoActionHandler(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['openFile'],
            OpenFileActionHandler(self, self._extAppMgr))

        self._actionHandlers.register(
            self._gui.actions['moveFiles'],
            MoveFilesActionHandler(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['renameFile'],
            RenameFileActionHandler(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['deleteFiles'],
            DeleteFilesActionHandler(self, self._dialogsFacade))




    def handlerSignals(self):
        return [([HandlerSignals.ITEM_CHANGED,
                  HandlerSignals.ITEM_CREATED,
                  HandlerSignals.ITEM_DELETED], self.refreshDir)]


    @property
    def repo(self):
        return self._repo

    def setRepo(self, repo):
        self._repo = repo
        if repo is not None:
            self.changeDir(repo.base_path)
            logger.debug("File Browser curr dir has been SET.")
        else:
            self.unsetDir()
            logger.debug("File Browser curr dir has been UNSET.")

    def checkActiveRepoIsNotNone(self):
        if self._repo is None:
            raise CurrentRepoIsNoneError("Current repository is None")


    @property
    def user(self):
        return self._user

    def setUser(self, user):
        self._user = user
        # TODO: update Gui according to the user change

    def checkActiveUserIsNotNone(self):
        if self._user is None:
            raise CurrentUserIsNoneError("Current user is None")


    def enable(self):
        self._enabled = True
        self.refreshDir()
        logger.debug("File Browser enabled.")


    def disable(self):
        self._enabled = False
        logger.debug("File Browser disabled.")


    @property
    def currDir(self):
        if self._currDir is None:
            raise NoneError()
        return self._currDir


    def repoBasePath(self):
        if self._repo is None:
            raise NoneError()
        return self._repo.base_path


    def itemIdsForDir(self, dirAbsPath):
        assert self._repo is not None
        dirRelPath = os.path.relpath(dirAbsPath, self._repo.base_path)
        itemIds = []
        try:
            uow = self._repo.createUnitOfWork()
            cmd = GetItemIdsWithFilesFrom(dirRelPath)
            itemIds = uow.executeCommand(cmd)
        finally:
            uow.close()
        return itemIds



    def listDir(self):
        if self._currDir is None:
            return []
        if self._listCache is None:
            self._rebuildListCache()
        return self._listCache


    def filesCount(self):
        if self._currDir is None:
            return 0
        if self._listCache is None:
            self._rebuildListCache()
        return len(self._listCache)


    def _rebuildListCache(self):
        if not self._enabled:
            self._listCache = []
            return

        def resetGuiTableRows(topRow, bottomRow):
            self._gui.resetTableRows(topRow, bottomRow)
            QtCore.QCoreApplication.processEvents()

        assert self._currDir is not None
        resultDirs = [FileInfo("..", FileInfo.DIR)]
        resultFiles = []
        for fname in os.listdir(self._currDir):
            absPath = os.path.join(self._currDir, fname)
            if os.path.isfile(absPath):
                resultFiles.append(FileInfo(absPath, FileInfo.FILE))
            elif os.path.isdir(absPath):
                resultDirs.append(FileInfo(absPath, FileInfo.DIR))
        self._listCache = resultDirs + resultFiles

        logger.debug("_rebuildListCache is about to start the FileInfoSearcherThread")
        self._thread = FileInfoSearcherThread(self, self._repo, self._listCache, self._mutex)
        self.connect(self._thread, QtCore.SIGNAL("progress"),
                         lambda topRow, bottomRow: resetGuiTableRows(topRow, bottomRow))
        self._thread.start()
        #self._thread.run()


    def changeDirUp(self):
        self.changeDir("..")


    def changeRelDir(self, relativeDir):
        absDir = os.path.join(self._currDir, relativeDir)
        absDir = os.path.normpath(absDir)
        self.changeDir(absDir)


    def refreshDir(self):
        if self._currDir is None:
            return
        self.changeDir(self._currDir)


    def changeDir(self, directory):
        if directory == ".":
            directory = self._currDir

        if directory == "..":
            directory, _ = os.path.split(self._currDir)

        if not os.path.exists(directory):
            raise NotExistError(directory + " not exists on the file system.")

        if not helpers.is_internal(directory, self.repoBasePath()):
            raise ValueError(directory +  " is outside the repository.")

        if os.path.isfile(directory):
            raise ValueError(directory + " is not a directory but a file.")

        assert os.path.isabs(directory)
        self.__setCurrDir(directory)


    def unsetDir(self):
        self.__setCurrDir(None)


    def __setCurrDir(self, directory):
        if self._thread is not None:
            self._thread.interrupt = True
            self._thread.wait()
        self._currDir = directory
        self._listCache = None
        self._mutex = QtCore.QMutex()
        self._gui.resetTableModel(self._mutex)

    def storeCurrentState(self):
        self._gui.saveColumnsWidth()
        self._gui.saveColumnsVisibility()


    def restoreRecentState(self):
        self._gui.restoreColumnsVisibility()
        self._gui.restoreColumnsWidth()
예제 #3
0
class FileBrowser(AbstractTool):

    TOOL_ID = "FileBrowserTool"

    def __init__(self, guiUpdater, dialogsFacade):
        super(FileBrowser, self).__init__()
        self._guiUpdater = guiUpdater
        self._actionHandlers = None
        self._dialogsFacade = dialogsFacade
        self.__dropFilesDialogs = DropFilesDialogsFacade(dialogsFacade)
        self._gui = None
        self._repo = None
        self._user = None
        self._currDir = None
        self._listCache = None
        self._mutex = None
        self._thread = None
        self._enabled = False
        self._extAppMgr = ExtAppMgr()

        self._guiUpdater.subscribe(self._extAppMgr,
                                   self._extAppMgr.updateState,
                                   [HandlerSignals.REGGATA_CONF_CHANGED])

        logger.debug("File Browser __init__ finished.")

    def id(self):
        return self.TOOL_ID

    def title(self):
        return self.tr("File Browser")

    def createGui(self, guiParent):
        self._gui = FileBrowserGui(guiParent, self)
        self._actionHandlers = ActionHandlerStorage(self._guiUpdater)
        logger.debug("File Browser GUI created.")
        return self._gui

    def __getGui(self):
        return self._gui

    gui = property(fget=__getGui)

    def connectActionsWithActionHandlers(self):
        assert len(self._gui.actions
                   ) > 0, "Actions should be already built in ToolGui"

        self._actionHandlers.register(
            self._gui.actions['editItems'],
            EditItemsActionHandlerFileBrowser(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['addFiles'],
            AddFilesToRepoActionHandler(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['openFile'],
            OpenFileActionHandler(self, self._extAppMgr))

        self._actionHandlers.register(
            self._gui.actions['moveFiles'],
            MoveFilesActionHandler(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['renameFile'],
            RenameFileActionHandler(self, self._dialogsFacade))

        self._actionHandlers.register(
            self._gui.actions['deleteFiles'],
            DeleteFilesActionHandler(self, self._dialogsFacade))

    def handlerSignals(self):
        return [([
            HandlerSignals.ITEM_CHANGED, HandlerSignals.ITEM_CREATED,
            HandlerSignals.ITEM_DELETED
        ], self.refreshDir)]

    @property
    def repo(self):
        return self._repo

    def setRepo(self, repo):
        self._repo = repo
        if repo is not None:
            self.changeDir(repo.base_path)
            logger.debug("File Browser curr dir has been SET.")
        else:
            self.unsetDir()
            logger.debug("File Browser curr dir has been UNSET.")

    def checkActiveRepoIsNotNone(self):
        if self._repo is None:
            raise CurrentRepoIsNoneError("Current repository is None")

    @property
    def user(self):
        return self._user

    def setUser(self, user):
        self._user = user
        # TODO: update Gui according to the user change

    def checkActiveUserIsNotNone(self):
        if self._user is None:
            raise CurrentUserIsNoneError("Current user is None")

    def enable(self):
        self._enabled = True
        self.refreshDir()
        logger.debug("File Browser enabled.")

    def disable(self):
        self._enabled = False
        logger.debug("File Browser disabled.")

    @property
    def currDir(self):
        if self._currDir is None:
            raise NoneError()
        return self._currDir

    def repoBasePath(self):
        if self._repo is None:
            raise NoneError()
        return self._repo.base_path

    def itemIdsForDir(self, dirAbsPath):
        assert self._repo is not None
        dirRelPath = os.path.relpath(dirAbsPath, self._repo.base_path)
        itemIds = []
        try:
            uow = self._repo.createUnitOfWork()
            cmd = GetItemIdsWithFilesFrom(dirRelPath)
            itemIds = uow.executeCommand(cmd)
        finally:
            uow.close()
        return itemIds

    def listDir(self):
        if self._currDir is None:
            return []
        if self._listCache is None:
            self._rebuildListCache()
        return self._listCache

    def filesCount(self):
        if self._currDir is None:
            return 0
        if self._listCache is None:
            self._rebuildListCache()
        return len(self._listCache)

    def _rebuildListCache(self):
        if not self._enabled:
            self._listCache = []
            return

        def resetGuiTableRows(topRow, bottomRow):
            self._gui.resetTableRows(topRow, bottomRow)
            QtCore.QCoreApplication.processEvents()

        assert self._currDir is not None
        resultDirs = [FileInfo("..", FileInfo.DIR)]
        resultFiles = []
        for fname in os.listdir(self._currDir):
            absPath = os.path.join(self._currDir, fname)
            if os.path.isfile(absPath):
                resultFiles.append(FileInfo(absPath, FileInfo.FILE))
            elif os.path.isdir(absPath):
                resultDirs.append(FileInfo(absPath, FileInfo.DIR))
        self._listCache = resultDirs + resultFiles

        logger.debug(
            "_rebuildListCache is about to start the FileInfoSearcherThread")
        self._thread = FileInfoSearcherThread(self, self._repo,
                                              self._listCache, self._mutex)
        self.connect(
            self._thread, QtCore.SIGNAL("progress"),
            lambda topRow, bottomRow: resetGuiTableRows(topRow, bottomRow))
        self._thread.start()
        #self._thread.run()

    def changeDirUp(self):
        self.changeDir("..")

    def changeRelDir(self, relativeDir):
        absDir = os.path.join(self._currDir, relativeDir)
        absDir = os.path.normpath(absDir)
        self.changeDir(absDir)

    def refreshDir(self):
        if self._currDir is None:
            return
        self.changeDir(self._currDir)

    def changeDir(self, directory):
        if directory == ".":
            directory = self._currDir

        if directory == "..":
            directory, _ = os.path.split(self._currDir)

        if not os.path.exists(directory):
            raise NotExistError(directory + " not exists on the file system.")

        if not helpers.is_internal(directory, self.repoBasePath()):
            raise ValueError(directory + " is outside the repository.")

        if os.path.isfile(directory):
            raise ValueError(directory + " is not a directory but a file.")

        assert os.path.isabs(directory)
        self.__setCurrDir(directory)

    def unsetDir(self):
        self.__setCurrDir(None)

    def __setCurrDir(self, directory):
        if self._thread is not None:
            self._thread.interrupt = True
            self._thread.wait()
        self._currDir = directory
        self._listCache = None
        self._mutex = QtCore.QMutex()
        self._gui.resetTableModel(self._mutex)

    def storeCurrentState(self):
        self._gui.saveColumnsWidth()
        self._gui.saveColumnsVisibility()

    def restoreRecentState(self):
        self._gui.restoreColumnsVisibility()
        self._gui.restoreColumnsWidth()