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()
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()
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()