def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self._view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() # self._show_toolbar = int(self._settings.value("show_toolbar", 1)) # fix migration issue from old settings show_toolbar = self._settings.value("show_toolbar", 1) if show_toolbar in ("true", "false"): show_toolbar = 1 self._show_toolbar = int(show_toolbar) self._add_created_date = int( self._settings.value("add_created_date", 1)) self._auto_save = int(self._settings.value("auto_save", 1)) self._auto_archive = int(self._settings.value("auto_archive", 1)) self._hide_future_tasks = int( self._settings.value("hide_future_tasks", 1)) self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._setIsModified(False) self._view.closeEventSignal.connect(self._view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller._view.setSelectedFiltersByNames(filters)
def __init__(self, view, dialogs_service, task_editor_service, args): super(MainController, self).__init__() self._args = args self._view = view self._dialogs_service = dialogs_service self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._settings = settings.Settings() self._setIsModified(False) self._view.closeEventSignal.connect(self._view_onCloseEvent)
def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self.view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() # self._show_toolbar = int(self._settings.value("show_toolbar", 1)) # fix migration issue from old settings show_toolbar = self._settings.value("show_toolbar", 1) if show_toolbar in ("true", "false"): show_toolbar = 1 self._show_toolbar = int(show_toolbar) self._show_completed = True self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._setIsModified(False) self.view.closeEventSignal.connect(self.view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller.view.setSelectedFiltersByNames(filters)
def _createMockFile(self): today = today = date.today().strftime('%Y-%m-%d') file = File() file.tasks.append(tasklib.Task('my task1 @context1')) file.tasks.append(tasklib.Task('my task2 @context1 @context2')) file.tasks.append(tasklib.Task('due:' + today + ' my task3 +project1 @context2')) file.tasks.append(tasklib.Task('due:' + today + ' my task4')) return file
def openFileByName(self, filename): logger.debug('MainController.openFileByName called with filename="{}"'.format(filename)) self._fileObserver.clear() self._file = File(self._todoFeatures) self._file.load(filename) self._loadFileToUI() self._settings.setLastOpenFile(filename) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename)
def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self._view = view self.settings = QtCore.QSettings() # handle the bad bool handling of qsettings self._show_toolbar = True if self.settings.value( "show_toolbar", "true") == "true" else False self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False # FIXME use of custom settings should be removed self._settings = settings.Settings() self._setIsModified(False) self._view.closeEventSignal.connect(self._view_onCloseEvent)
def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self.view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() self._show_completed = True self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._setIsModified(False) self._fileObserver.fileChangetSig.connect(self.openFileByName) self.view.closeEventSignal.connect(self.view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller.view.setSelectedFiltersByNames(filters) self.hasTrayIcon = False self._menu_controller.updateRecentFileActions()
def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self._view = view self.settings = QtCore.QSettings() # handle the bad bool handling of qsettings self._show_toolbar = True if self.settings.value("show_toolbar", "true") == "true" else False self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False # FIXME use of custom settings should be removed self._settings = settings.Settings() self._setIsModified(False) self._view.closeEventSignal.connect(self._view_onCloseEvent)
def __init__(self, view, dialogs, args): super(MainController, self).__init__() self._args = args self.view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() self._show_completed = True self._dialogs = dialogs self._file = File() self._fileObserver = FileObserver(self, self._file) self._initControllers() self._is_modified = False self._setIsModified(False) self._fileObserver.fileChangetSig.connect(self.openFileByName) self.view.closeEventSignal.connect(self.view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller.view.setSelectedFiltersByNames(filters) self.hasTrayIcon = False self._menu_controller.updateRecentFileActions()
def new(self): if self._canExit(): self._file = File() self._loadFileToUI()
class MainController(QtCore.QObject): _show_toolbar = QtCore.pyqtSignal(int) def __init__(self, view, dialogs, args): super(MainController, self).__init__() self._args = args self.view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() self._show_completed = True self._dialogs = dialogs self._file = File() self._fileObserver = FileObserver(self, self._file) self._initControllers() self._is_modified = False self._setIsModified(False) self._fileObserver.fileChangetSig.connect(self.openFileByName) self.view.closeEventSignal.connect(self.view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller.view.setSelectedFiltersByNames(filters) self.hasTrayIcon = False self._menu_controller.updateRecentFileActions() def auto_save(self): if int(self._settings.value("auto_save", 1)): self.save() def _initControllers(self): self._initFiltersTree() self._initTasksList() self._initContextualMenu() self._initActions() self._initMenuBar() self._initToolBar() self._initSearchText() def _initMenuBar(self): menu = self.view.menuBar() self._menu_controller = MenuController(self, menu) def _initActions(self): self.filterViewAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/sidepane.png'), self.tr('Show &Filters'), self) self.filterViewAction.setCheckable(True) self.filterViewAction.setShortcuts(['Ctrl+Shift+F']) self.filterViewAction.triggered.connect(self._toggleFilterView) self.showFutureAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/future.png'), self.tr('Show future &Tasks'), self) self.showFutureAction.setCheckable(True) self.showFutureAction.setShortcuts(['Ctrl+Shift+T']) self.showFutureAction.triggered.connect(self._toggleShowFuture) self.showCompletedAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/show_completed.png'), self.tr('Show &Completed tasks'), self) self.showCompletedAction.setCheckable(True) self.showCompletedAction.setShortcuts(['Ctrl+Shift+C']) self.showCompletedAction.triggered.connect(self._toggleShowCompleted) self.archiveAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/archive.png'), self.tr('&Archive completed tasks'), self) self.archiveAction.setShortcuts(['Ctrl+Shift+A']) self.archiveAction.triggered.connect(self._archive_all_done_tasks) self.showToolBarAction = QtWidgets.QAction(self.tr('Show tool&Bar'), self) self.showToolBarAction.setCheckable(True) self.showToolBarAction.setShortcuts(['Ctrl+Shift+B']) self.showToolBarAction.triggered.connect(self._toggleShowToolBar) self.showSearchAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/ActionSearch.png'), self.tr('Show search bar'), self) self.showSearchAction.setCheckable(True) self.showSearchAction.setShortcuts(['Ctrl+F']) self.showSearchAction.triggered.connect(self._toggleShowSearch) def _initToolBar(self): toolbar = self.view.addToolBar("Main Toolbar") toolbar.setObjectName("mainToolbar") toolbar.addAction(self.filterViewAction) toolbar.addAction(self.showFutureAction) toolbar.addAction(self.showCompletedAction) toolbar.addAction(self.showSearchAction) toolbar.addSeparator() toolbar.addAction(self._menu_controller.openAction) toolbar.addAction(self._menu_controller.saveAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.createTaskAction) toolbar.addAction(self._tasks_list_controller.createTaskActionOnTemplate) toolbar.addAction(self._tasks_list_controller.editTaskAction) toolbar.addAction(self._tasks_list_controller.copySelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.completeSelectedTasksAction) if int(self._settings.value("show_delete", 0)): toolbar.addAction(self._tasks_list_controller.deleteSelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.increasePrioritySelectedTasksAction) toolbar.addAction(self._tasks_list_controller.decreasePrioritySelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self.archiveAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.addLinkAction) self._show_toolbar.connect(toolbar.setVisible) def _toggleShowToolBar(self): if self.showToolBarAction.isChecked(): self._settings.setValue("show_toolbar", 1) self._toolbar_visibility_changed(1) else: self._settings.setValue("show_toolbar", 0) self._toolbar_visibility_changed(0) def _toggleShowSearch(self): if self.showSearchAction.isChecked(): self._settings.setValue("show_search", 1) self.view.tasks_view.tasks_search_view.setVisible(True) else: self._settings.setValue("show_search", 0) self.view.tasks_view.tasks_search_view.setVisible(False) self.view.tasks_view.tasks_search_view.setText("") def _toggleShowCompleted(self): if self.showCompletedAction.isChecked(): self._settings.setValue("show_completed_tasks", 1) self._show_completed = True self.updateFilters() else: self._settings.setValue("show_completed_tasks", 0) self._show_completed = False self.updateFilters() self._filters_tree_controller.showFilters(self._file, self._show_completed) def _toggleShowFuture(self): if self.showFutureAction.isChecked(): self._settings.setValue("show_future_tasks", 1) self.updateFilters() else: self._settings.setValue("show_future_tasks", 0) self.updateFilters() def _restoreShowFuture(self): val = int(self._settings.value("show_future_tasks", 1)) if val: self.showFutureAction.setChecked(True) self._toggleShowFuture() else: self.showFutureAction.setChecked(False) self._toggleShowFuture() def _toggleFilterView(self): if self.filterViewAction.isChecked(): self._settings.setValue("show_filter_tree", 1) self._filters_tree_controller.view.show() else: self._settings.setValue("splitter_pos", self.view.centralWidget().sizes()) self._settings.setValue("show_filter_tree", 0) self._filters_tree_controller.view.hide() def _restoreFilterView(self): val = int(self._settings.value("show_filter_tree", 1)) if val: self.filterViewAction.setChecked(True) self._toggleFilterView() else: self.filterViewAction.setChecked(False) self._toggleFilterView() def _toolbar_visibility_changed(self, val): self._show_toolbar.emit(val) def exit(self): self.view.close() sys.exit() def getView(self): return self.view def show(self): self._updateView() self.view.show() self._updateTitle() if self._args.file: filename = self._args.file else: filename = self._settings.value("last_open_file") if filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) if self._args.quickadd: self._tasks_list_controller.createTask() self.save() self.exit() def _initFiltersTree(self): controller = self._filters_tree_controller = \ FiltersTreeController(self.view.filters_tree_view) controller.filterSelectionChanged.connect( self._onFilterSelectionChanged) def _onFilterSelectionChanged(self, filters): self._applyFilters(filters=filters) def _applyFilters(self, filters=None, searchText=None): # First we filter with filters tree if filters is None: filters = self._filters_tree_controller.view.getSelectedFilters() tasks = tasklib.filterTasks(filters, self._file.tasks) # Then with our search text if searchText is None: searchText = self.view.tasks_view.tasks_search_view.getSearchText() tasks = tasklib.filterTasks([SimpleTextFilter(searchText)], tasks) # with future filter if needed if not self.showFutureAction.isChecked(): tasks = tasklib.filterTasks([FutureFilter()], tasks) # with complete filter if needed if not CompleteTasksFilter() in filters and not self.showCompletedAction.isChecked(): tasks = tasklib.filterTasks([IncompleteTasksFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initSearchText(self): self.view.tasks_view.tasks_search_view.searchTextChanged.connect( self._onSearchTextChanged) def _onSearchTextChanged(self, searchText): self._applyFilters(searchText=searchText) def _initTasksList(self): controller = self._tasks_list_controller = \ TasksListController(self.view.tasks_view.tasks_list_view, self._file) controller.taskCreated.connect(self._tasks_list_taskCreated) controller.taskModified.connect(self._tasks_list_taskModified) controller.taskDeleted.connect(self._tasks_list_taskDeleted) controller.taskArchived.connect(self._tasks_list_taskArchived) def _initContextualMenu(self): # Context menu # controller.view.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self._tasks_list_controller.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self._tasks_list_controller.view.customContextMenuRequested.connect(self.showContextMenu) self._contextMenu = QtWidgets.QMenu(self.view) self._contextMenu.addAction(self._tasks_list_controller.createTaskAction) self._contextMenu.addAction(self._tasks_list_controller.createTaskActionOnTemplate) self._contextMenu.addAction(self._tasks_list_controller.editTaskAction) self._contextMenu.addAction(self._tasks_list_controller.copySelectedTasksAction) self._contextMenu.addAction(self._tasks_list_controller.addLinkAction) self._contextMenu.addSeparator() self._contextMenu.addAction(self._tasks_list_controller.completeSelectedTasksAction) if int(self._settings.value("show_delete", 1)): self._contextMenu.addAction(self._tasks_list_controller.deleteSelectedTasksAction) self._contextMenu.addSeparator() self._contextMenu.addAction(self._tasks_list_controller.increasePrioritySelectedTasksAction) self._contextMenu.addAction(self._tasks_list_controller.decreasePrioritySelectedTasksAction) def showContextMenu(self, position): tasks = self._tasks_list_controller.view.getSelectedTasks() if tasks: self._contextMenu.exec_(self._tasks_list_controller.view.mapToGlobal(position)) def _tasks_list_taskDeleted(self, task): self._file.tasks.remove(task) self._onFileUpdated() def _tasks_list_taskCreated(self, task): self._file.tasks.append(task) self._onFileUpdated() def _tasks_list_taskModified(self): self._onFileUpdated() def _tasks_list_taskArchived(self, task): self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _archive_all_done_tasks(self): done = [task for task in self._file.tasks if task.is_complete] for task in done: self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _onFileUpdated(self): self._filters_tree_controller.showFilters(self._file, self._show_completed) self._setIsModified(True) self.auto_save() def _canExit(self): if not self._is_modified: return True button = self._dialogs.showSaveDiscardCancel(self.tr('Unsaved changes...')) if button == QtWidgets.QMessageBox.Save: self.save() return True else: return button == QtWidgets.QMessageBox.Discard def view_onCloseEvent(self, closeEvent): if (self.hasTrayIcon and int(self._settings.value("close_to_tray", 0))): self.view.hide() closeEvent.ignore() return if self._canExit(): if self.filterViewAction.isChecked(): # we only save size if it is visible self._settings.setValue("splitter_pos", self.view.centralWidget().sizes()) self._settings.setValue("current_filters", self._filters_tree_controller.view.getSelectedFilterNames()) self._settings.setValue("main_window_geometry", self.view.saveGeometry()) self._settings.setValue("main_window_state", self.view.saveState()) closeEvent.accept() else: closeEvent.ignore() def _setIsModified(self, is_modified): self._is_modified = is_modified self._updateTitle() self._menu_controller.saveAction.setEnabled(is_modified) self._menu_controller.revertAction.setEnabled(is_modified) def save(self): logger.debug('MainController.save called.') self._fileObserver.clear() filename = self._file.filename ok = True if not filename: (filename, ok) = \ QtWidgets.QFileDialog.getSaveFileName(self.view, filter=FILENAME_FILTERS) if ok and filename: self._file.save(filename) self._settings.setValue("last_open_file", filename) self._settings.sync() self._setIsModified(False) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _updateTitle(self): title = 'QTodoTxt - ' if self._file.filename: filename = os.path.basename(self._file.filename) title += filename else: title += 'Untitled' if self._is_modified: title += ' (*)' self.view.setWindowTitle(title) def open(self): (filename, ok) = \ QtWidgets.QFileDialog.getOpenFileName(self.view, filter=FILENAME_FILTERS) if ok and filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def new(self): if self._canExit(): self._file = File() self._loadFileToUI() def revert(self): if self._dialogs.showConfirm(self.tr('Revert to saved file (and lose unsaved changes)?')): try: self.openFileByName(self._file.filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def openFileByName(self, filename): logger.debug('MainController.openFileByName called with filename="{}"'.format(filename)) self._fileObserver.clear() try: self._file.load(filename) except Exception as ex: currentfile = self._settings.value("last_open_file", "") if currentfile == filename: self._dialogs.showError(self.tr("Current file '{}' is not available.\nException: {}"). format(filename, ex)) else: self._dialogs.showError(self.tr("Error opening file: {}.\n Exception:{}").format(filename, ex)) return self._loadFileToUI() self._settings.setValue("last_open_file", filename) self._settings.sync() logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) self.updateRecentFile() def updateRecentFile(self): lastOpenedArray = self._menu_controller.getRecentFileNames() if self._file.filename in lastOpenedArray: lastOpenedArray.remove(self._file.filename) lastOpenedArray = lastOpenedArray[:self._menu_controller.maxRecentFiles] lastOpenedArray.insert(0, self._file.filename) self._settings.setValue("lastOpened", lastOpenedArray[: self._menu_controller.maxRecentFiles]) self._menu_controller.updateRecentFileActions() def _loadFileToUI(self): self._setIsModified(False) self._filters_tree_controller.showFilters(self._file, self._show_completed) def _updateView(self): wgeo = self._settings.value("main_window_geometry", None) if wgeo is not None: self.view.restoreGeometry(wgeo) wstate = self._settings.value("main_window_state", None) if wstate is not None: self.view.restoreState(wstate) splitterPosition = self._settings.value("splitter_pos", (200, 400)) splitterPosition = [int(x) for x in splitterPosition] self.view.centralWidget().setSizes(splitterPosition) self._restoreShowCompleted() self._restoreFilterView() self._restoreShowFuture() self._restoreShowToolBar() self._restoreShowSearch() def _restoreShowCompleted(self): val = int(self._settings.value("show_completed_tasks", 1)) if val: self._show_completed = True self.showCompletedAction.setChecked(True) else: self._show_completed = False self.showCompletedAction.setChecked(False) def _restoreShowToolBar(self): val = int(self._settings.value("show_toolbar", 1)) if val: self._toolbar_visibility_changed(1) self.showToolBarAction.setChecked(True) else: self._toolbar_visibility_changed(0) self.showToolBarAction.setChecked(False) def _restoreShowSearch(self): val = int(self._settings.value("show_search", 1)) if val: self.view.tasks_view.tasks_search_view.setVisible(True) self.showSearchAction.setChecked(True) else: self.view.tasks_view.tasks_search_view.setVisible(False) self.showSearchAction.setChecked(False) def updateFilters(self): self._onFilterSelectionChanged(self._filters_tree_controller.view.getSelectedFilters()) def toggleVisible(self): if self.view.isMinimized() or self.view.isHidden(): self.view.show() self.view.activateWindow() else: self.view.hide() def anotherInstanceEvent(self, dir): tFile = dir + "/qtodo.tmp" if not os.path.isfile(tFile): return time.sleep(0.01) f = open(tFile, 'r+b') line = f.readline() line = line.strip() if line == b"1": self.view.show() self.view.activateWindow() if line == b"2": self.view.show() self.view.activateWindow() self._tasks_list_controller.createTask() f.close() os.remove(tFile)
class MainController(QtCore.QObject): def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self._view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() # self._show_toolbar = int(self._settings.value("show_toolbar", 1)) # fix migration issue from old settings show_toolbar = self._settings.value("show_toolbar", 1) if show_toolbar in ("true", "false"): show_toolbar = 1 self._show_toolbar = int(show_toolbar) self._add_created_date = int( self._settings.value("add_created_date", 1)) self._auto_save = int(self._settings.value("auto_save", 1)) self._auto_archive = int(self._settings.value("auto_archive", 1)) self._hide_future_tasks = int( self._settings.value("hide_future_tasks", 1)) self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._setIsModified(False) self._view.closeEventSignal.connect(self._view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller._view.setSelectedFiltersByNames(filters) def auto_save(self): if self._auto_save: self.save() def _initControllers(self): self._initFiltersTree() self._initTasksList() self._initMenuBar() self._initToolBar() self._initFilterText() def _initMenuBar(self): menu = self._view.menuBar() self._menu_controller = MenuController(self, menu) def _initToolBar(self): toolbar = self._view.addToolBar("Main Toolbar") toolbar.setObjectName("mainToolbar") toolbar.addAction(self._menu_controller.openAction) toolbar.addAction(self._menu_controller.saveAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.createTaskAction) toolbar.addAction(self._tasks_list_controller.editTaskAction) toolbar.addSeparator() toolbar.addAction( self._tasks_list_controller.completeSelectedTasksAction) toolbar.addAction( self._tasks_list_controller.deleteSelectedTasksAction) toolbar.addSeparator() toolbar.addAction( self._tasks_list_controller.increasePrioritySelectedTasksAction) toolbar.addAction( self._tasks_list_controller.decreasePrioritySelectedTasksAction) toolbar.visibilityChanged.connect(self._toolbar_visibility_changed) if not self._show_toolbar: toolbar.hide() def _toolbar_visibility_changed(self, val): self._show_toolbar = int(val) def exit(self): self._view.close() sys.exit() def getView(self): return self._view def show(self): self._updateView() self._view.show() self._updateTitle() self._updateCreatePref() self._updateAutoSavePref() self._updateAutoArchivePref() self._updateHideFutureTasksPref() if self._args.file: filename = self._args.file else: filename = self._settings.value("last_open_file") if filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) if self._args.quickadd: self._tasks_list_controller.createTask() self.save() self.exit() def _initFiltersTree(self): controller = self._filters_tree_controller = \ FiltersTreeController(self._view.filters_tree_view) controller.filterSelectionChanged.connect( self._onFilterSelectionChanged) def _onFilterSelectionChanged(self, filters): # First we filter with filters tree treeTasks = tasklib.filterTasks(filters, self._file.tasks) # Then with our filter text filterText = self._view.tasks_view.tasks_filter.getText() tasks = tasklib.filterTasks([SimpleTextFilter(filterText)], treeTasks) # And finally with future filter if needed # TODO: refactor all that filters if self._hide_future_tasks: tasks = tasklib.filterTasks([FutureFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initFilterText(self): self._view.tasks_view.tasks_filter.filterTextChanged.connect( self._onFilterTextChanged) def _onFilterTextChanged(self, text): # First we filter with filters tree filters = self._filters_tree_controller._view.getSelectedFilters() treeTasks = tasklib.filterTasks(filters, self._file.tasks) # Then with our filter text tasks = tasklib.filterTasks([SimpleTextFilter(text)], treeTasks) # And finally with future filter if needed # TODO: refactor all that filters if self._hide_future_tasks: tasks = tasklib.filterTasks([FutureFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initTasksList(self): controller = self._tasks_list_controller = \ TasksListController(self._view.tasks_view.tasks_list_view, self._task_editor_service) controller.taskCreated.connect(self._tasks_list_taskCreated) controller.taskModified.connect(self._tasks_list_taskModified) controller.taskDeleted.connect(self._tasks_list_taskDeleted) controller.taskArchived.connect(self._tasks_list_taskArchived) # Context menu # controller._view.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) controller._view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) controller._view.customContextMenuRequested.connect( self.showContextMenu) self._contextMenu = QtGui.QMenu() self._contextMenu.addAction(self._tasks_list_controller.editTaskAction) self._contextMenu.addSeparator() self._contextMenu.addAction( self._tasks_list_controller.completeSelectedTasksAction) self._contextMenu.addAction( self._tasks_list_controller.deleteSelectedTasksAction) self._contextMenu.addSeparator() self._contextMenu.addAction( self._tasks_list_controller.increasePrioritySelectedTasksAction) self._contextMenu.addAction( self._tasks_list_controller.decreasePrioritySelectedTasksAction) def showContextMenu(self, position): tasks = self._tasks_list_controller._view.getSelectedTasks() if tasks: self._contextMenu.exec_( self._tasks_list_controller._view.mapToGlobal(position)) def _tasks_list_taskDeleted(self, task): self._file.tasks.remove(task) self._onFileUpdated() def _tasks_list_taskCreated(self, task): self._file.tasks.append(task) self._onFileUpdated() def _tasks_list_taskModified(self, task): self._onFileUpdated() def _tasks_list_taskArchived(self, task): self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _onFileUpdated(self): self._filters_tree_controller.showFilters(self._file) self._task_editor_service.updateValues(self._file) self._setIsModified(True) self.auto_save() def _canExit(self): if not self._is_modified: return True button = self._dialogs.showSaveDiscardCancel('Unsaved changes...') if button == QtGui.QMessageBox.Save: self.save() return True else: return button == QtGui.QMessageBox.Discard def _view_onCloseEvent(self, closeEvent): if self._canExit(): self._settings.setValue("show_toolbar", self._show_toolbar) self._settings.setValue("splitter_pos", self._view.centralWidget().sizes()) self._settings.setValue( "current_filters", self._filters_tree_controller._view.getSelectedFilterNames()) self._settings.setValue("main_window_geometry", self._view.saveGeometry()) self._settings.setValue("main_window_state", self._view.saveState()) self._settings.setValue("add_created_date", self._add_created_date) self._settings.setValue("auto_save", self._auto_save) self._settings.setValue("auto_archive", self._auto_archive) self._settings.setValue("hide_future_tasks", self._hide_future_tasks) closeEvent.accept() else: closeEvent.ignore() def _setIsModified(self, is_modified): self._is_modified = is_modified self._updateTitle() self._menu_controller.saveAction.setEnabled(is_modified) self._menu_controller.revertAction.setEnabled(is_modified) def save(self): logger.debug('MainController.save called.') self._fileObserver.clear() filename = self._file.filename ok = True if not filename: (filename, ok) = \ QtGui.QFileDialog.getSaveFileName(self._view, filter=FILENAME_FILTERS) if ok and filename: self._file.save(filename) self._settings.setValue("last_open_file", filename) self._settings.sync() self._setIsModified(False) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _updateTitle(self): title = 'QTodoTxt - ' if self._file.filename: filename = os.path.basename(self._file.filename) title += filename else: title += 'Untitled' if self._is_modified: title += ' (*)' self._view.setWindowTitle(title) def open(self): (filename, ok) = \ QtGui.QFileDialog.getOpenFileName(self._view, filter=FILENAME_FILTERS) if ok and filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def new(self): if self._canExit(): self._file = File() self._loadFileToUI() def revert(self): if self._dialogs.showConfirm( 'Revert to saved file (and lose unsaved changes)?'): try: self.openFileByName(self._file.filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def openFileByName(self, filename): logger.debug( 'MainController.openFileByName called with filename="{}"'.format( filename)) self._fileObserver.clear() self._file.load(filename) self._loadFileToUI() self._settings.setValue("last_open_file", filename) self._settings.sync() logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _loadFileToUI(self): self._setIsModified(False) self._filters_tree_controller.showFilters(self._file) self._task_editor_service.updateValues(self._file) def _updateCreatePref(self): self._menu_controller.changeCreatedDateState(self._add_created_date) def _updateAutoSavePref(self): self._menu_controller.changeAutoSaveState(self._auto_save) def _updateAutoArchivePref(self): self._menu_controller.changeAutoArchiveState(self._auto_archive) def _updateHideFutureTasksPref(self): self._menu_controller.changeHideFutureTasksState( self._hide_future_tasks) def _updateView(self): self._view.restoreGeometry( self._settings.value("main_window_geometry")) self._view.restoreState(self._settings.value("main_window_state")) splitterPosition = self._settings.value("splitter_pos", None) if splitterPosition: splitterPosition = [int(x) for x in splitterPosition] self._view.centralWidget().setSizes(splitterPosition) def toggleCreatedDate(self): self._add_created_date = int(not self._add_created_date) self._settings.setValue("add_created_date", self._add_created_date) self._settings.sync() def toggleAutoSave(self): self._auto_save = int(not self._auto_save) self._settings.setValue("auto_save", self._auto_save) self._settings.sync() def toggleAutoArchive(self): self._auto_archive = int(not self._auto_archive) self._settings.setValue("auto_archive", self._auto_archive) self._settings.sync() def toggleHideFutureTasks(self): self._hide_future_tasks = int(not self._hide_future_tasks) self._settings.setValue("hide_future_tasks", self._hide_future_tasks) self._settings.sync() self._onFilterSelectionChanged( self._filters_tree_controller._view.getSelectedFilters()) def toggleVisible(self): if self._view.isMinimized(): self._view.showNormal() self._view.activateWindow() else: self._view.showMinimized()
class MainController(QtCore.QObject): def __init__(self, view, dialogs_service, task_editor_service, args): super(MainController, self).__init__() self._args = args self._view = view self._dialogs_service = dialogs_service self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._settings = settings.Settings() self._setIsModified(False) self._view.closeEventSignal.connect(self._view_onCloseEvent) def autoSave(self): if self._settings.getAutoSave(): self.save() def _initControllers(self): self._initFiltersTree() self._initTasksList() self._initMenuBar() self._initFilterText() def _initMenuBar(self): menu = self._view.menuBar() self._menu_controller = MenuController(self, menu) def exit(self): self._view.close() sys.exit() def getView(self): return self._view def show(self): self._view.show() self._updateTitle() self._settings.load() self._updateCreatePref() self._updateAutoSavePref() self._updateAutoArchivePref() self._updateHideFutureTasksPref() self._updateView() if self._args.file: filename = self._args.file[0] else: filename = self._settings.getLastOpenFile() if filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs_service.showError(str(ex)) if self._args.quickadd: self._tasks_list_controller.createTask() self.save() self.exit() def _initFiltersTree(self): controller = self._filters_tree_controller = \ FiltersTreeController(self._view.filters_tree_view) controller.filterSelectionChanged.connect( self._onFilterSelectionChanged) def _onFilterSelectionChanged(self, filters): # First we filter with filters tree treeTasks = todolib.filterTasks(filters, self._file.tasks) # Then with our filter text filterText = self._view.tasks_view.filter_tasks.getText() tasks = todolib.filterTasks([SimpleTextFilter(filterText)], treeTasks) # And finally with future filter if needed # TODO: refactor all that filters if self._settings.getHideFutureTasks(): tasks = todolib.filterTasks([FutureFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initFilterText(self): self._view.tasks_view.filter_tasks.filterTextChanged.connect( self._onFilterTextChanged) def _onFilterTextChanged(self, text): # First we filter with filters tree filters = self._filters_tree_controller._view.getSelectedFilters() treeTasks = todolib.filterTasks(filters, self._file.tasks) # Then with our filter text tasks = todolib.filterTasks([SimpleTextFilter(text)], treeTasks) # And finally with future filter if needed # TODO: refactor all that filters if self._settings.getHideFutureTasks(): tasks = todolib.filterTasks([FutureFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initTasksList(self): controller = self._tasks_list_controller = \ TasksListController(self._view.tasks_view.tasks_list_view, self._task_editor_service) controller.taskCreated.connect(self._tasks_list_taskCreated) controller.taskModified.connect(self._tasks_list_taskModified) controller.taskDeleted.connect(self._tasks_list_taskDeleted) controller.taskArchived.connect(self._tasks_list_taskArchived) def _tasks_list_taskDeleted(self, task): self._file.tasks.remove(task) self._onFileUpdated() def _tasks_list_taskCreated(self, task): self._file.tasks.append(task) self._onFileUpdated() def _tasks_list_taskModified(self, task): self._onFileUpdated() def _tasks_list_taskArchived(self, task): self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _onFileUpdated(self): self._filters_tree_controller.showFilters(self._file) self._task_editor_service.updateValues(self._file) self._setIsModified(True) self.autoSave() def _canExit(self): if not self._is_modified: return True button = self._dialogs_service.showSaveDiscardOrCancel( 'Unsaved changes...') if button == QtGui.QMessageBox.Save: self.save() return True else: return button == QtGui.QMessageBox.Discard def _view_onCloseEvent(self, closeEvent): if self._canExit(): self._saveView() closeEvent.accept() else: closeEvent.ignore() def _saveView(self): viewSize = self._view.size() viewPosition = self._view.pos() splitterPosition = self._view.centralWidget().sizes() self._settings.setViewHeight(viewSize.height()) self._settings.setViewWidth(viewSize.width()) self._settings.setViewPositionX(viewPosition.x()) self._settings.setViewPositionY(viewPosition.y()) self._settings.setViewSlidderPosition(splitterPosition) def _setIsModified(self, is_modified): self._is_modified = is_modified self._updateTitle() self._menu_controller.saveAction.setEnabled(is_modified) self._menu_controller.revertAction.setEnabled(is_modified) def save(self): logger.debug('MainController.save called.') self._fileObserver.clear() filename = self._file.filename ok = True if not filename: (filename, ok) = \ QtGui.QFileDialog.getSaveFileName(self._view, filter=FILENAME_FILTERS) if ok and filename: self._file.save(filename) self._settings.setLastOpenFile(filename) self._setIsModified(False) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _updateTitle(self): title = 'QTodoTxt - ' if self._file.filename: filename = os.path.basename(self._file.filename) title += filename else: title += 'Untitled' if self._is_modified: title += ' (*)' self._view.setWindowTitle(title) def open(self): (filename, ok) = \ QtGui.QFileDialog.getOpenFileName(self._view, filter=FILENAME_FILTERS) if ok and filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs_service.showError(str(ex)) def new(self): if self._canExit(): self._file = File() self._loadFileToUI() def revert(self): if self._dialogs_service.showConfirm( 'Revert to saved file (and lose unsaved changes)?'): try: self.openFileByName(self._file.filename) except ErrorLoadingFile as ex: self._dialogs_service.showError(str(ex)) def openFileByName(self, filename): logger.debug( 'MainController.openFileByName called with filename="{}"'.format( filename)) self._fileObserver.clear() self._file.load(filename) self._loadFileToUI() self._settings.setLastOpenFile(filename) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _loadFileToUI(self): self._setIsModified(False) self._filters_tree_controller.showFilters(self._file) self._task_editor_service.updateValues(self._file) def _updateCreatePref(self): self._menu_controller.changeCreatedDateState( bool(self._settings.getCreateDate())) def _updateAutoSavePref(self): self._menu_controller.changeAutoSaveState( bool(self._settings.getAutoSave())) def _updateAutoArchivePref(self): self._menu_controller.changeAutoArchiveState( bool(self._settings.getAutoArchive())) def _updateHideFutureTasksPref(self): self._menu_controller.changeHideFutureTasksState( bool(self._settings.getHideFutureTasks())) def _updateView(self): height = self._settings.getViewHeight() width = self._settings.getViewWidth() if height and width: self._view.resize(width, height) positionX = self._settings.getViewPositionX() positionY = self._settings.getViewPositionY() if positionX and positionY: self._view.move(positionX, positionY) slidderPosition = self._settings.getViewSlidderPosition() if slidderPosition: self._view.centralWidget().setSizes(slidderPosition) def createdDate(self): if self._settings.getCreateDate(): self._settings.setCreateDate(False) else: self._settings.setCreateDate(True) def toggleAutoSave(self): if self._settings.getAutoSave(): self._settings.setAutoSave(False) else: self._settings.setAutoSave(True) def toggleAutoArchive(self): if self._settings.getAutoArchive(): self._settings.setAutoArchive(False) else: self._settings.setAutoArchive(True) def toggleHideFutureTasks(self): if self._settings.getHideFutureTasks(): self._settings.setHideFutureTasks(False) else: self._settings.setHideFutureTasks(True) self._onFilterSelectionChanged( self._filters_tree_controller._view.getSelectedFilters()) def toggleVisible(self): if self._view.isMinimized(): self._view.showNormal() self._view.activateWindow() else: self._view.showMinimized()
class TestFile(unittest.TestCase): def setUp(self): self.file = File() self.tmpfile = mkstemp(text=True)[1] def tearDown(self): try: remove(self.tmpfile) except FileNotFoundError: pass except OSError as ex: # maintain compatibility with Python 3.2 if ex.errno != 2: raise except: raise def saveAndReload(self): self.file.save(self.tmpfile) self.file = File() self.file.load(self.tmpfile) def test_single_task(self): text = 'due:1999-10-10 do something +project1 @context1' self.file.tasks.append(Task(text)) self.saveAndReload() self.assertEqual(self.file.tasks[0].text, text) self.assertEqual(self.file.tasks[0].contexts, ['context1']) self.assertEqual(self.file.tasks[0].projects, ['project1']) self.assertFalse(self.file.tasks[0].is_complete) self.assertFalse(self.file.tasks[0].priority) self.assertEqual(self.file.tasks[0].due, date(1999, 10, 10)) def test_two_tasks(self): task1 = 'do something +project1 @context1' task2 = '(A) do something else +project1 @context2' self.file.tasks.extend([Task(task1), Task(task2)]) self.saveAndReload() self.assertEqual(self.file.tasks[0].text, task2) self.assertEqual(self.file.tasks[1].text, task1) def test_five_tasks(self): task1 = Task('do something +project1 @context1') task2 = Task('(A) do something else +project1 @context2') task3 = Task('do something else +project1 @context2') task4 = Task('something else +project1 @context2') task5 = Task('abc +project1 @context2') self.file.tasks.extend([task1, task2, task3, task4, task5]) self.saveAndReload() self.assertEqual(self.file.tasks[0].text, task2.text) self.assertEqual(self.file.tasks[1].text, task5.text) self.assertEqual(self.file.tasks[2].text, task1.text) self.assertEqual(self.file.tasks[3].text, task3.text) self.assertEqual(self.file.tasks[4].text, task4.text) def test_get_all_contexts(self): self.file.tasks.extend([ Task('x task with @context1'), Task('task with @context2'), Task('task with @context1 and @context2'), Task('task with @context1 and @context2 and @context3') ]) self.saveAndReload() self.assertEqual(self.file.getAllContexts(), { 'context1': 2, 'context2': 3, 'context3': 1 }) def test_get_all_incl_completed_contexts(self): self.file.tasks.extend([ Task('x task with @context1'), Task('task with @context2'), Task('task with @context1 and @context2'), Task('x task with @context1 and @context2 and @context3') ]) self.saveAndReload() self.assertEqual(self.file.getAllContexts(True), { 'context1': 1, 'context2': 2, 'context3': 0 }) def test_get_all_projects(self): self.file.tasks.extend([ Task('x task with +project1'), Task('task with +project2'), Task('task with +project1 and +project2'), Task('task with +project1 and +project2 and +project3') ]) self.saveAndReload() self.assertEqual(self.file.getAllProjects(), { 'project1': 2, 'project2': 3, 'project3': 1 }) def test_get_all_due_ranges(self): today = date.today().strftime('%Y-%m-%d') yesterday = (date.today() - timedelta(days=1)).strftime('%Y-%m-%d') self.file.tasks.extend([ Task('x due:' + today + ' completed task of today'), Task('due:' + today + ' first task of today'), Task('due:' + today + ' second task of today'), Task('due:' + yesterday + ' task of yesterday'), ]) self.saveAndReload() self.assertEqual(self.file.getAllDueRanges()[0], { 'Today': 2, 'This week': 2, 'This month': 2, 'Overdue': 1 }) self.assertIsInstance(self.file.getAllDueRanges()[1], dict) def test_get_all_projects_incl_completed(self): self.file.tasks.extend([ Task('x task with +project1'), Task('task with +project2'), Task('task with +project1 and +project2'), Task('x task with +project1 and +project2 and +project3') ]) self.saveAndReload() self.assertEqual(self.file.getAllProjects(True), { 'project1': 1, 'project2': 2, 'project3': 0 }) def test_load_empty_filename(self): self.assertRaises(ErrorLoadingFile, self.file.load, '') def test_load_nonexisting_file(self): remove(self.tmpfile) self.assertRaises(ErrorLoadingFile, self.file.load, self.tmpfile)
def setUp(self): self.file = File() self.tmpfile = mkstemp(text=True)[1]
def new(self): if self._canExit(): self._file = File(self._todoFeatures) self._loadFileToUI()
class MainController(QtCore.QObject): _show_toolbar = QtCore.pyqtSignal(int) def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self.view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() self._show_completed = True self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._setIsModified(False) self._fileObserver.fileChangetSig.connect(self.openFileByName) self.view.closeEventSignal.connect(self.view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller.view.setSelectedFiltersByNames(filters) self.hasTrayIcon = False self._menu_controller.updateRecentFileActions() def auto_save(self): if int(self._settings.value("auto_save", 1)): self.save() def _initControllers(self): self._initFiltersTree() self._initTasksList() self._initContextualMenu() self._initActions() self._initMenuBar() self._initToolBar() self._initSearchText() def _initMenuBar(self): menu = self.view.menuBar() self._menu_controller = MenuController(self, menu) def _initActions(self): self.filterViewAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/sidepane.png'), self.tr('Show &Filters'), self) self.filterViewAction.setCheckable(True) self.filterViewAction.setShortcuts(['Ctrl+Shift+F']) self.filterViewAction.triggered.connect(self._toggleFilterView) self.showFutureAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/future.png'), self.tr('Show future &Tasks'), self) self.showFutureAction.setCheckable(True) self.showFutureAction.setShortcuts(['Ctrl+Shift+T']) self.showFutureAction.triggered.connect(self._toggleShowFuture) self.showCompletedAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/show_completed.png'), self.tr('Show &Completed tasks'), self) self.showCompletedAction.setCheckable(True) self.showCompletedAction.setShortcuts(['Ctrl+Shift+C']) self.showCompletedAction.triggered.connect(self._toggleShowCompleted) self.archiveAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/archive.png'), self.tr('&Archive completed tasks'), self) self.archiveAction.setShortcuts(['Ctrl+Shift+A']) self.archiveAction.triggered.connect(self._archive_all_done_tasks) self.showToolBarAction = QtWidgets.QAction(self.tr('Show tool&Bar'), self) self.showToolBarAction.setCheckable(True) self.showToolBarAction.setShortcuts(['Ctrl+Shift+B']) self.showToolBarAction.triggered.connect(self._toggleShowToolBar) self.showSearchAction = QtWidgets.QAction(QtGui.QIcon(self.view.style + '/resources/ActionSearch.png'), self.tr('Show search bar'), self) self.showSearchAction.setCheckable(True) self.showSearchAction.setShortcuts(['Ctrl+F']) self.showSearchAction.triggered.connect(self._toggleShowSearch) def _initToolBar(self): toolbar = self.view.addToolBar("Main Toolbar") toolbar.setObjectName("mainToolbar") toolbar.addAction(self.filterViewAction) toolbar.addAction(self.showFutureAction) toolbar.addAction(self.showCompletedAction) toolbar.addAction(self.showSearchAction) toolbar.addSeparator() toolbar.addAction(self._menu_controller.openAction) toolbar.addAction(self._menu_controller.saveAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.createTaskAction) toolbar.addAction(self._tasks_list_controller.createTaskActionOnTemplate) toolbar.addAction(self._tasks_list_controller.editTaskAction) toolbar.addAction(self._tasks_list_controller.copySelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.completeSelectedTasksAction) if int(self._settings.value("show_delete", 0)): toolbar.addAction(self._tasks_list_controller.deleteSelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.increasePrioritySelectedTasksAction) toolbar.addAction(self._tasks_list_controller.decreasePrioritySelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self.archiveAction) self._show_toolbar.connect(toolbar.setVisible) def _toggleShowToolBar(self): if self.showToolBarAction.isChecked(): self._settings.setValue("show_toolbar", 1) self._toolbar_visibility_changed(1) else: self._settings.setValue("show_toolbar", 0) self._toolbar_visibility_changed(0) def _toggleShowSearch(self): if self.showSearchAction.isChecked(): self._settings.setValue("show_search", 1) self.view.tasks_view.tasks_search_view.setVisible(True) else: self._settings.setValue("show_search", 0) self.view.tasks_view.tasks_search_view.setVisible(False) self.view.tasks_view.tasks_search_view.setText("") def _toggleShowCompleted(self): if self.showCompletedAction.isChecked(): self._settings.setValue("show_completed_tasks", 1) self._show_completed = True self.updateFilters() else: self._settings.setValue("show_completed_tasks", 0) self._show_completed = False self.updateFilters() self._filters_tree_controller.showFilters(self._file, self._show_completed) def _toggleShowFuture(self): if self.showFutureAction.isChecked(): self._settings.setValue("show_future_tasks", 1) self.updateFilters() else: self._settings.setValue("show_future_tasks", 0) self.updateFilters() def _restoreShowFuture(self): val = int(self._settings.value("show_future_tasks", 1)) if val: self.showFutureAction.setChecked(True) self._toggleShowFuture() else: self.showFutureAction.setChecked(False) self._toggleShowFuture() def _toggleFilterView(self): if self.filterViewAction.isChecked(): self._settings.setValue("show_filter_tree", 1) self._filters_tree_controller.view.show() else: self._settings.setValue("splitter_pos", self.view.centralWidget().sizes()) self._settings.setValue("show_filter_tree", 0) self._filters_tree_controller.view.hide() def _restoreFilterView(self): val = int(self._settings.value("show_filter_tree", 1)) if val: self.filterViewAction.setChecked(True) self._toggleFilterView() else: self.filterViewAction.setChecked(False) self._toggleFilterView() def _toolbar_visibility_changed(self, val): self._show_toolbar.emit(val) def exit(self): self.view.close() sys.exit() def getView(self): return self.view def show(self): self._updateView() self.view.show() self._updateTitle() if self._args.file: filename = self._args.file else: filename = self._settings.value("last_open_file") if filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) if self._args.quickadd: self._tasks_list_controller.createTask() self.save() self.exit() def _initFiltersTree(self): controller = self._filters_tree_controller = \ FiltersTreeController(self.view.filters_tree_view) controller.filterSelectionChanged.connect( self._onFilterSelectionChanged) def _onFilterSelectionChanged(self, filters): self._applyFilters(filters=filters) def _applyFilters(self, filters=None, searchText=None): # First we filter with filters tree if filters is None: filters = self._filters_tree_controller.view.getSelectedFilters() tasks = tasklib.filterTasks(filters, self._file.tasks) # Then with our search text if searchText is None: searchText = self.view.tasks_view.tasks_search_view.getSearchText() tasks = tasklib.filterTasks([SimpleTextFilter(searchText)], tasks) # with future filter if needed if not self.showFutureAction.isChecked(): tasks = tasklib.filterTasks([FutureFilter()], tasks) # with complete filter if needed if not CompleteTasksFilter() in filters and not self.showCompletedAction.isChecked(): tasks = tasklib.filterTasks([IncompleteTasksFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initSearchText(self): self.view.tasks_view.tasks_search_view.searchTextChanged.connect( self._onSearchTextChanged) def _onSearchTextChanged(self, searchText): self._applyFilters(searchText=searchText) def _initTasksList(self): controller = self._tasks_list_controller = \ TasksListController(self.view.tasks_view.tasks_list_view, self._task_editor_service) controller.taskCreated.connect(self._tasks_list_taskCreated) controller.taskModified.connect(self._tasks_list_taskModified) controller.taskDeleted.connect(self._tasks_list_taskDeleted) controller.taskArchived.connect(self._tasks_list_taskArchived) def _initContextualMenu(self): # Context menu # controller.view.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self._tasks_list_controller.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self._tasks_list_controller.view.customContextMenuRequested.connect(self.showContextMenu) self._contextMenu = QtWidgets.QMenu(self.view) self._contextMenu.addAction(self._tasks_list_controller.createTaskAction) self._contextMenu.addAction(self._tasks_list_controller.createTaskActionOnTemplate) self._contextMenu.addAction(self._tasks_list_controller.editTaskAction) self._contextMenu.addAction(self._tasks_list_controller.copySelectedTasksAction) self._contextMenu.addSeparator() self._contextMenu.addAction(self._tasks_list_controller.completeSelectedTasksAction) if int(self._settings.value("show_delete", 1)): self._contextMenu.addAction(self._tasks_list_controller.deleteSelectedTasksAction) self._contextMenu.addSeparator() self._contextMenu.addAction(self._tasks_list_controller.increasePrioritySelectedTasksAction) self._contextMenu.addAction(self._tasks_list_controller.decreasePrioritySelectedTasksAction) def showContextMenu(self, position): tasks = self._tasks_list_controller.view.getSelectedTasks() if tasks: self._contextMenu.exec_(self._tasks_list_controller.view.mapToGlobal(position)) def _tasks_list_taskDeleted(self, task): self._file.tasks.remove(task) self._onFileUpdated() def _tasks_list_taskCreated(self, task): self._file.tasks.append(task) self._onFileUpdated() def _tasks_list_taskModified(self, task): self._onFileUpdated() def _tasks_list_taskArchived(self, task): self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _archive_all_done_tasks(self): done = [task for task in self._file.tasks if task.is_complete] for task in done: self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _onFileUpdated(self): self._filters_tree_controller.showFilters(self._file, self._show_completed) self._task_editor_service.updateValues(self._file) self._setIsModified(True) self.auto_save() def _canExit(self): if not self._is_modified: return True button = self._dialogs.showSaveDiscardCancel(self.tr('Unsaved changes...')) if button == QtWidgets.QMessageBox.Save: self.save() return True else: return button == QtWidgets.QMessageBox.Discard def view_onCloseEvent(self, closeEvent): if (self.hasTrayIcon and int(self._settings.value("close_to_tray", 0))): self.view.hide() closeEvent.ignore() return if self._canExit(): if self.filterViewAction.isChecked(): # we only save size if it is visible self._settings.setValue("splitter_pos", self.view.centralWidget().sizes()) self._settings.setValue("current_filters", self._filters_tree_controller.view.getSelectedFilterNames()) self._settings.setValue("main_window_geometry", self.view.saveGeometry()) self._settings.setValue("main_window_state", self.view.saveState()) closeEvent.accept() else: closeEvent.ignore() def _setIsModified(self, is_modified): self._is_modified = is_modified self._updateTitle() self._menu_controller.saveAction.setEnabled(is_modified) self._menu_controller.revertAction.setEnabled(is_modified) def save(self): logger.debug('MainController.save called.') self._fileObserver.clear() filename = self._file.filename ok = True if not filename: (filename, ok) = \ QtWidgets.QFileDialog.getSaveFileName(self.view, filter=FILENAME_FILTERS) if ok and filename: self._file.save(filename) self._settings.setValue("last_open_file", filename) self._settings.sync() self._setIsModified(False) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _updateTitle(self): title = 'QTodoTxt - ' if self._file.filename: filename = os.path.basename(self._file.filename) title += filename else: title += 'Untitled' if self._is_modified: title += ' (*)' self.view.setWindowTitle(title) def open(self): (filename, ok) = \ QtWidgets.QFileDialog.getOpenFileName(self.view, filter=FILENAME_FILTERS) if ok and filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def new(self): if self._canExit(): self._file = File() self._loadFileToUI() def revert(self): if self._dialogs.showConfirm(self.tr('Revert to saved file (and lose unsaved changes)?')): try: self.openFileByName(self._file.filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def openFileByName(self, filename): logger.debug('MainController.openFileByName called with filename="{}"'.format(filename)) self._fileObserver.clear() try: self._file.load(filename) except Exception as ex: currentfile = self._settings.value("last_open_file", "") if currentfile == filename: self._dialogs.showError(self.tr("Current file '{}' is not available.\nException: {}"). format(filename, ex)) else: self._dialogs.showError(self.tr("Error opening file: {}.\n Exception:{}").format(filename, ex)) return self._loadFileToUI() self._settings.setValue("last_open_file", filename) self._settings.sync() logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) self.updateRecentFile() def updateRecentFile(self): lastOpenedArray = self._menu_controller.getRecentFileNames() if self._file.filename in lastOpenedArray: lastOpenedArray.remove(self._file.filename) lastOpenedArray = lastOpenedArray[:self._menu_controller.maxRecentFiles] lastOpenedArray.insert(0, self._file.filename) self._settings.setValue("lastOpened", lastOpenedArray[: self._menu_controller.maxRecentFiles]) self._menu_controller.updateRecentFileActions() def _loadFileToUI(self): self._setIsModified(False) self._filters_tree_controller.showFilters(self._file, self._show_completed) self._task_editor_service.updateValues(self._file) def _updateView(self): wgeo = self._settings.value("main_window_geometry", None) if wgeo is not None: self.view.restoreGeometry(wgeo) wstate = self._settings.value("main_window_state", None) if wstate is not None: self.view.restoreState(wstate) splitterPosition = self._settings.value("splitter_pos", (200, 400)) splitterPosition = [int(x) for x in splitterPosition] self.view.centralWidget().setSizes(splitterPosition) self._restoreShowCompleted() self._restoreFilterView() self._restoreShowFuture() self._restoreShowToolBar() self._restoreShowSearch() def _restoreShowCompleted(self): val = int(self._settings.value("show_completed_tasks", 1)) if val: self._show_completed = True self.showCompletedAction.setChecked(True) else: self._show_completed = False self.showCompletedAction.setChecked(False) def _restoreShowToolBar(self): val = int(self._settings.value("show_toolbar", 1)) if val: self._toolbar_visibility_changed(1) self.showToolBarAction.setChecked(True) else: self._toolbar_visibility_changed(0) self.showToolBarAction.setChecked(False) def _restoreShowSearch(self): val = int(self._settings.value("show_search", 1)) if val: self.view.tasks_view.tasks_search_view.setVisible(True) self.showSearchAction.setChecked(True) else: self.view.tasks_view.tasks_search_view.setVisible(False) self.showSearchAction.setChecked(False) def updateFilters(self): self._onFilterSelectionChanged(self._filters_tree_controller.view.getSelectedFilters()) def toggleVisible(self): if self.view.isMinimized() or self.view.isHidden(): self.view.show() self.view.activateWindow() else: self.view.hide() def anotherInstanceEvent(self, dir): tFile = dir + "/qtodo.tmp" if not os.path.isfile(tFile): return time.sleep(0.01) f = open(tFile, 'r+b') line = f.readline() line = line.strip() if line == b"1": self.view.show() self.view.activateWindow() if line == b"2": self.view.show() self.view.activateWindow() self._tasks_list_controller.createTask() f.close() os.remove(tFile)
class TestFile(unittest.TestCase): def setUp(self): self.file = File() self.tmpfile = mkstemp(text=True)[1] def tearDown(self): try: remove(self.tmpfile) except FileNotFoundError: pass except OSError as ex: # maintain compatibility with Python 3.2 if ex.errno != 2: raise except: raise def saveAndReaload(self): self.file.save(self.tmpfile) self.file = File() self.file.load(self.tmpfile) def test_single_task(self): text = 'do something +project1 @context1' self.file.tasks.append(Task(text)) self.saveAndReaload() self.assertEqual(self.file.tasks[0].text, text) self.assertEqual(self.file.tasks[0].contexts, ['context1']) self.assertEqual(self.file.tasks[0].projects, ['project1']) self.assertEqual(self.file.tasks[0].is_complete, False) self.assertEqual(self.file.tasks[0].priority, None) def test_two_tasks(self): task1 = 'do something +project1 @context1' task2 = '(A) do something else +project1 @context2' self.file.tasks.extend([ Task(task1), Task(task2) ]) self.saveAndReaload() self.assertEqual(self.file.tasks[0].text, task2) self.assertEqual(self.file.tasks[1].text, task1) def test_five_tasks(self): task1 = Task('do something +project1 @context1') task2 = Task('(A) do something else +project1 @context2') task3 = Task('do something else +project1 @context2') task4 = Task('something else +project1 @context2') task5 = Task('abc +project1 @context2') self.file.tasks.extend([task1, task2, task3, task4, task5]) self.saveAndReaload() self.assertEqual(self.file.tasks[0].text, task2.text) self.assertEqual(self.file.tasks[1].text, task5.text) self.assertEqual(self.file.tasks[2].text, task1.text) self.assertEqual(self.file.tasks[3].text, task3.text) self.assertEqual(self.file.tasks[4].text, task4.text) def test_get_all_contexts(self): self.file.tasks.extend([ Task('x task with @context1'), Task('task with @context2'), Task('task with @context1 and @context2'), Task('task with @context1 and @context2 and @context3') ]) self.saveAndReaload() self.assertEqual(self.file.getAllContexts(), {'context1': 2, 'context2': 3, 'context3': 1}) def test_get_all_completed_contexts(self): self.file.tasks.extend([ Task('x task with @context1'), Task('task with @context2'), Task('task with @context1 and @context2'), Task('x task with @context1 and @context2 and @context3') ]) self.saveAndReaload() self.assertEqual(self.file.getAllCompletedContexts(), {'context1': 2, 'context2': 1, 'context3': 1}) def test_get_all_projects(self): self.file.tasks.extend([ Task('x task with +project1'), Task('task with +project2'), Task('task with +project1 and +project2'), Task('task with +project1 and +project2 and +project3') ]) self.saveAndReaload() self.assertEqual(self.file.getAllProjects(), {'project1': 2, 'project2': 3, 'project3': 1}) def test_get_all_completed_projects(self): self.file.tasks.extend([ Task('x task with +project1'), Task('task with +project2'), Task('task with +project1 and +project2'), Task('x task with +project1 and +project2 and +project3') ]) self.saveAndReaload() self.assertEqual(self.file.getAllCompletedProjects(), {'project1': 2, 'project2': 1, 'project3': 1}) def test_load_empty_filename(self): self.assertRaises(ErrorLoadingFile, self.file.load, '') def test_load_nonexisting_file(self): remove(self.tmpfile) self.assertRaises(ErrorLoadingFile, self.file.load, self.tmpfile)
class TestFile(unittest.TestCase): def setUp(self): self.file = File() self.tmpfile = mkstemp(text=True)[1] def tearDown(self): try: remove(self.tmpfile) except FileNotFoundError: pass except OSError as ex: # maintain compatibility with Python 3.2 if ex.errno != 2: raise except: raise def saveAndReload(self): self.file.save(self.tmpfile) self.file = File() self.file.load(self.tmpfile) def test_single_task(self): text = 'due:1999-10-10 do something +project1 @context1' self.file.tasks.append(Task(text)) self.saveAndReload() self.assertEqual(self.file.tasks[0].text, text) self.assertEqual(self.file.tasks[0].contexts, ['context1']) self.assertEqual(self.file.tasks[0].projects, ['project1']) self.assertEqual(self.file.tasks[0].is_complete, False) self.assertEqual(self.file.tasks[0].priority, None) self.assertEqual(self.file.tasks[0].due, '1999-10-10') def test_two_tasks(self): task1 = 'do something +project1 @context1' task2 = '(A) do something else +project1 @context2' self.file.tasks.extend([ Task(task1), Task(task2) ]) self.saveAndReload() self.assertEqual(self.file.tasks[0].text, task2) self.assertEqual(self.file.tasks[1].text, task1) def test_five_tasks(self): task1 = Task('do something +project1 @context1') task2 = Task('(A) do something else +project1 @context2') task3 = Task('do something else +project1 @context2') task4 = Task('something else +project1 @context2') task5 = Task('abc +project1 @context2') self.file.tasks.extend([task1, task2, task3, task4, task5]) self.saveAndReload() self.assertEqual(self.file.tasks[0].text, task2.text) self.assertEqual(self.file.tasks[1].text, task5.text) self.assertEqual(self.file.tasks[2].text, task1.text) self.assertEqual(self.file.tasks[3].text, task3.text) self.assertEqual(self.file.tasks[4].text, task4.text) def test_get_all_contexts(self): self.file.tasks.extend([ Task('x task with @context1'), Task('task with @context2'), Task('task with @context1 and @context2'), Task('task with @context1 and @context2 and @context3') ]) self.saveAndReload() self.assertEqual(self.file.getAllContexts(), {'context1': 2, 'context2': 3, 'context3': 1}) def test_get_all_completed_contexts(self): self.file.tasks.extend([ Task('x task with @context1'), Task('task with @context2'), Task('task with @context1 and @context2'), Task('x task with @context1 and @context2 and @context3') ]) self.saveAndReload() self.assertEqual(self.file.getAllCompletedContexts(), {'context1': 2, 'context2': 1, 'context3': 1}) def test_get_all_projects(self): self.file.tasks.extend([ Task('x task with +project1'), Task('task with +project2'), Task('task with +project1 and +project2'), Task('task with +project1 and +project2 and +project3') ]) self.saveAndReload() self.assertEqual(self.file.getAllProjects(), {'project1': 2, 'project2': 3, 'project3': 1}) def test_get_all_due_ranges(self): today = date.today().strftime('%Y-%m-%d') yesterday = (date.today() - timedelta(days=1)).strftime('%Y-%m-%d') self.file.tasks.extend([ Task('x due:' + today + ' completed task of today'), Task('due:' + today + ' first task of today'), Task('due:' + today + ' second task of today'), Task('due:' + yesterday + ' task of yesterday'), ]) self.saveAndReload() self.assertEqual(self.file.getAllDueRanges()[0], {'Today': 2, 'This week': 2, 'This month': 2, 'Overdue': 1}) self.assertIsInstance(self.file.getAllDueRanges()[1], dict) def test_get_all_completed_projects(self): self.file.tasks.extend([ Task('x task with +project1'), Task('task with +project2'), Task('task with +project1 and +project2'), Task('x task with +project1 and +project2 and +project3') ]) self.saveAndReload() self.assertEqual(self.file.getAllCompletedProjects(), {'project1': 2, 'project2': 1, 'project3': 1}) def test_load_empty_filename(self): self.assertRaises(ErrorLoadingFile, self.file.load, '') def test_load_nonexisting_file(self): remove(self.tmpfile) self.assertRaises(ErrorLoadingFile, self.file.load, self.tmpfile)
class MainController(QtCore.QObject): def __init__(self, view, dialogs_service, task_editor_service, args): super(MainController, self).__init__() self._args = args self._view = view self._dialogs_service = dialogs_service self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._settings = settings.Settings() self._setIsModified(False) self._view.closeEventSignal.connect(self._view_onCloseEvent) def autoSave(self): if self._settings.getAutoSave(): self.save() def _initControllers(self): self._initFiltersTree() self._initTasksList() self._initMenuBar() self._initFilterText() def _initMenuBar(self): menu = self._view.menuBar() self._menu_controller = MenuController(self, menu) def exit(self): self._view.close() sys.exit() def getView(self): return self._view def show(self): self._view.show() self._updateTitle() self._settings.load() self._updateCreatePref() self._updateAutoSavePref() self._updateAutoArchivePref() self._updateHideFutureTasksPref() self._updateView() if self._args.file: filename = self._args.file[0] else: filename = self._settings.getLastOpenFile() if filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs_service.showError(str(ex)) if self._args.quickadd: self._tasks_list_controller.createTask() self.save() self.exit() def _initFiltersTree(self): controller = self._filters_tree_controller = \ FiltersTreeController(self._view.filters_tree_view) controller.filterSelectionChanged.connect( self._onFilterSelectionChanged) def _onFilterSelectionChanged(self, filters): # First we filter with filters tree treeTasks = todolib.filterTasks(filters, self._file.tasks) # Then with our filter text filterText = self._view.tasks_view.filter_tasks.getText() tasks = todolib.filterTasks([SimpleTextFilter(filterText)], treeTasks) # And finally with future filter if needed # TODO: refactor all that filters if self._settings.getHideFutureTasks(): tasks = todolib.filterTasks([FutureFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initFilterText(self): self._view.tasks_view.filter_tasks.filterTextChanged.connect( self._onFilterTextChanged) def _onFilterTextChanged(self, text): # First we filter with filters tree filters = self._filters_tree_controller._view.getSelectedFilters() treeTasks = todolib.filterTasks(filters, self._file.tasks) # Then with our filter text tasks = todolib.filterTasks([SimpleTextFilter(text)], treeTasks) # And finally with future filter if needed # TODO: refactor all that filters if self._settings.getHideFutureTasks(): tasks = todolib.filterTasks([FutureFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initTasksList(self): controller = self._tasks_list_controller = \ TasksListController(self._view.tasks_view.tasks_list_view, self._task_editor_service) controller.taskCreated.connect(self._tasks_list_taskCreated) controller.taskModified.connect(self._tasks_list_taskModified) controller.taskDeleted.connect(self._tasks_list_taskDeleted) controller.taskArchived.connect(self._tasks_list_taskArchived) def _tasks_list_taskDeleted(self, task): self._file.tasks.remove(task) self._onFileUpdated() def _tasks_list_taskCreated(self, task): self._file.tasks.append(task) self._onFileUpdated() def _tasks_list_taskModified(self, task): self._onFileUpdated() def _tasks_list_taskArchived(self, task): self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _onFileUpdated(self): self._filters_tree_controller.showFilters(self._file) self._task_editor_service.updateValues(self._file) self._setIsModified(True) self.autoSave() def _canExit(self): if not self._is_modified: return True button = self._dialogs_service.showSaveDiscardOrCancel('Unsaved changes...') if button == QtGui.QMessageBox.Save: self.save() return True else: return button == QtGui.QMessageBox.Discard def _view_onCloseEvent(self, closeEvent): if self._canExit(): self._saveView() closeEvent.accept() else: closeEvent.ignore() def _saveView(self): viewSize = self._view.size() viewPosition = self._view.pos() splitterPosition = self._view.centralWidget().sizes() self._settings.setViewHeight(viewSize.height()) self._settings.setViewWidth(viewSize.width()) self._settings.setViewPositionX(viewPosition.x()) self._settings.setViewPositionY(viewPosition.y()) self._settings.setViewSlidderPosition(splitterPosition) def _setIsModified(self, is_modified): self._is_modified = is_modified self._updateTitle() self._menu_controller.saveAction.setEnabled(is_modified) self._menu_controller.revertAction.setEnabled(is_modified) def save(self): logger.debug('MainController.save called.') self._fileObserver.clear() filename = self._file.filename ok = True if not filename: (filename, ok) = \ QtGui.QFileDialog.getSaveFileName(self._view, filter=FILENAME_FILTERS) if ok and filename: self._file.save(filename) self._settings.setLastOpenFile(filename) self._setIsModified(False) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _updateTitle(self): title = 'QTodoTxt - ' if self._file.filename: filename = os.path.basename(self._file.filename) title += filename else: title += 'Untitled' if self._is_modified: title += ' (*)' self._view.setWindowTitle(title) def open(self): (filename, ok) = \ QtGui.QFileDialog.getOpenFileName(self._view, filter=FILENAME_FILTERS) if ok and filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs_service.showError(str(ex)) def new(self): if self._canExit(): self._file = File() self._loadFileToUI() def revert(self): if self._dialogs_service.showConfirm('Revert to saved file (and lose unsaved changes)?'): try: self.openFileByName(self._file.filename) except ErrorLoadingFile as ex: self._dialogs_service.showError(str(ex)) def openFileByName(self, filename): logger.debug('MainController.openFileByName called with filename="{}"'.format(filename)) self._fileObserver.clear() self._file.load(filename) self._loadFileToUI() self._settings.setLastOpenFile(filename) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _loadFileToUI(self): self._setIsModified(False) self._filters_tree_controller.showFilters(self._file) self._task_editor_service.updateValues(self._file) def _updateCreatePref(self): self._menu_controller.changeCreatedDateState(bool(self._settings.getCreateDate())) def _updateAutoSavePref(self): self._menu_controller.changeAutoSaveState(bool(self._settings.getAutoSave())) def _updateAutoArchivePref(self): self._menu_controller.changeAutoArchiveState(bool(self._settings.getAutoArchive())) def _updateHideFutureTasksPref(self): self._menu_controller.changeHideFutureTasksState(bool(self._settings.getHideFutureTasks())) def _updateView(self): height = self._settings.getViewHeight() width = self._settings.getViewWidth() if height and width: self._view.resize(width, height) positionX = self._settings.getViewPositionX() positionY = self._settings.getViewPositionY() if positionX and positionY: self._view.move(positionX, positionY) slidderPosition = self._settings.getViewSlidderPosition() if slidderPosition: self._view.centralWidget().setSizes(slidderPosition) def createdDate(self): if self._settings.getCreateDate(): self._settings.setCreateDate(False) else: self._settings.setCreateDate(True) def toggleAutoSave(self): if self._settings.getAutoSave(): self._settings.setAutoSave(False) else: self._settings.setAutoSave(True) def toggleAutoArchive(self): if self._settings.getAutoArchive(): self._settings.setAutoArchive(False) else: self._settings.setAutoArchive(True) def toggleHideFutureTasks(self): if self._settings.getHideFutureTasks(): self._settings.setHideFutureTasks(False) else: self._settings.setHideFutureTasks(True) self._onFilterSelectionChanged(self._filters_tree_controller._view.getSelectedFilters()) def toggleVisible(self): if self._view.isMinimized(): self._view.showNormal() self._view.activateWindow() else: self._view.showMinimized()
def saveAndReload(self): self.file.save(self.tmpfile) self.file = File() self.file.load(self.tmpfile)
def saveAndReaload(self): self.file.save(self.tmpfile) self.file = File() self.file.load(self.tmpfile)
class MainController(QtCore.QObject): def __init__(self, view, dialogs, task_editor_service, args): super(MainController, self).__init__() self._args = args self.view = view # use object variable for setting only used in this class # others are accessed through QSettings self._settings = QtCore.QSettings() # self._show_toolbar = int(self._settings.value("show_toolbar", 1)) # fix migration issue from old settings show_toolbar = self._settings.value("show_toolbar", 1) if show_toolbar in ("true", "false"): show_toolbar = 1 self._show_toolbar = int(show_toolbar) self._show_completed = True self._dialogs = dialogs self._task_editor_service = task_editor_service self._initControllers() self._file = File() self._fileObserver = FileObserver(self, self._file) self._is_modified = False self._setIsModified(False) self.view.closeEventSignal.connect(self.view_onCloseEvent) filters = self._settings.value("current_filters", ["All"]) self._filters_tree_controller.view.setSelectedFiltersByNames(filters) def auto_save(self): if int(self._settings.value("auto_save", 1)): self.save() def _initControllers(self): self._initFiltersTree() self._initTasksList() self._initMenuBar() self._initActions() self._initToolBar() self._initSearchText() def _initMenuBar(self): menu = self.view.menuBar() self._menu_controller = MenuController(self, menu) def _initActions(self): self.filterViewAction = QtWidgets.QAction(getIcon('sidepane.png'), '&Show Filters', self) self.filterViewAction.setCheckable(True) # action.setShortcuts(['Ctrl+E']) # what should it be? self.filterViewAction.triggered.connect(self._toggleFilterView) self.showFutureAction = QtWidgets.QAction(getIcon('future.png'), '&Show Future Tasks', self) self.showFutureAction.setCheckable(True) # action.setShortcuts(['Ctrl+E']) # what should it be? self.showFutureAction.triggered.connect(self._toggleShowFuture) self.showCompletedAction = QtWidgets.QAction(getIcon('show_completed.png'), '&Show Completed Tasks', self) self.showCompletedAction.setCheckable(True) # action.setShortcuts(['Ctrl+E']) # what should it be? self.showCompletedAction.triggered.connect(self._toggleShowCompleted) self.archiveAction = QtWidgets.QAction(getIcon('archive.png'), '&Archive Completed Tasks', self) # action.setShortcuts(['Ctrl+E']) # what should it be? self.archiveAction.triggered.connect(self._archive_all_done_tasks) def _initToolBar(self): toolbar = self.view.addToolBar("Main Toolbar") toolbar.setObjectName("mainToolbar") toolbar.addAction(self.filterViewAction) toolbar.addAction(self.showFutureAction) toolbar.addAction(self.showCompletedAction) toolbar.addSeparator() toolbar.addAction(self._menu_controller.openAction) toolbar.addAction(self._menu_controller.saveAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.createTaskAction) toolbar.addAction(self._tasks_list_controller.editTaskAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.completeSelectedTasksAction) toolbar.addAction(self._tasks_list_controller.deleteSelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self._tasks_list_controller.increasePrioritySelectedTasksAction) toolbar.addAction(self._tasks_list_controller.decreasePrioritySelectedTasksAction) toolbar.addSeparator() toolbar.addAction(self.archiveAction) toolbar.visibilityChanged.connect(self._toolbar_visibility_changed) if not self._show_toolbar: toolbar.hide() def _toggleShowCompleted(self): if self.showCompletedAction.isChecked(): self._settings.setValue("show_completed_tasks", 1) self._show_completed = True self.updateFilters() else: self._settings.setValue("show_completed_tasks", 0) self._show_completed = False self.updateFilters() self._filters_tree_controller.showFilters(self._file, self._show_completed) def _toggleShowFuture(self): if self.showFutureAction.isChecked(): self._settings.setValue("show_future_tasks", 1) self.updateFilters() else: self._settings.setValue("show_future_tasks", 0) self.updateFilters() def _restoreShowFuture(self): val = int(self._settings.value("show_future_tasks", 1)) if val: self.showFutureAction.setChecked(True) self._toggleShowFuture() else: self.showFutureAction.setChecked(False) self._toggleShowFuture() def _toggleFilterView(self): if self.filterViewAction.isChecked(): self._settings.setValue("show_filter_tree", 1) self._filters_tree_controller.view.show() else: self._settings.setValue("splitter_pos", self.view.centralWidget().sizes()) self._settings.setValue("show_filter_tree", 0) self._filters_tree_controller.view.hide() def _restoreFilterView(self): val = int(self._settings.value("show_filter_tree", 1)) if val: self.filterViewAction.setChecked(True) self._toggleFilterView() else: self.filterViewAction.setChecked(False) self._toggleFilterView() def _toolbar_visibility_changed(self, val): self._show_toolbar = int(val) def exit(self): self.view.close() sys.exit() def getView(self): return self.view def show(self): self._updateView() self.view.show() self._updateTitle() if self._args.file: filename = self._args.file else: filename = self._settings.value("last_open_file") if filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) if self._args.quickadd: self._tasks_list_controller.createTask() self.save() self.exit() def _initFiltersTree(self): controller = self._filters_tree_controller = \ FiltersTreeController(self.view.filters_tree_view) controller.filterSelectionChanged.connect( self._onFilterSelectionChanged) def _onFilterSelectionChanged(self, filters): self._applyFilters(filters=filters) def _applyFilters(self, filters=None, searchText=None): # First we filter with filters tree if filters is None: filters = self._filters_tree_controller.view.getSelectedFilters() tasks = tasklib.filterTasks(filters, self._file.tasks) # Then with our search text if searchText is None: searchText = self.view.tasks_view.tasks_search_view.getSearchText() tasks = tasklib.filterTasks([SimpleTextFilter(searchText)], tasks) # with future filter if needed if not self.showFutureAction.isChecked(): tasks = tasklib.filterTasks([FutureFilter()], tasks) # with complete filter if needed if not CompleteTasksFilter() in filters and not self.showCompletedAction.isChecked(): tasks = tasklib.filterTasks([IncompleteTasksFilter()], tasks) self._tasks_list_controller.showTasks(tasks) def _initSearchText(self): self.view.tasks_view.tasks_search_view.searchTextChanged.connect( self._onSearchTextChanged) def _onSearchTextChanged(self, searchText): self._applyFilters(searchText=searchText) def _initTasksList(self): controller = self._tasks_list_controller = \ TasksListController(self.view.tasks_view.tasks_list_view, self._task_editor_service) controller.taskCreated.connect(self._tasks_list_taskCreated) controller.taskModified.connect(self._tasks_list_taskModified) controller.taskDeleted.connect(self._tasks_list_taskDeleted) controller.taskArchived.connect(self._tasks_list_taskArchived) # Context menu # controller.view.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) controller.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) controller.view.customContextMenuRequested.connect(self.showContextMenu) self._contextMenu = QtWidgets.QMenu() self._contextMenu.addAction(self._tasks_list_controller.editTaskAction) self._contextMenu.addSeparator() self._contextMenu.addAction(self._tasks_list_controller.completeSelectedTasksAction) self._contextMenu.addAction(self._tasks_list_controller.deleteSelectedTasksAction) self._contextMenu.addSeparator() self._contextMenu.addAction(self._tasks_list_controller.increasePrioritySelectedTasksAction) self._contextMenu.addAction(self._tasks_list_controller.decreasePrioritySelectedTasksAction) def showContextMenu(self, position): tasks = self._tasks_list_controller.view.getSelectedTasks() if tasks: self._contextMenu.exec_(self._tasks_list_controller.view.mapToGlobal(position)) def _tasks_list_taskDeleted(self, task): self._file.tasks.remove(task) self._onFileUpdated() def _tasks_list_taskCreated(self, task): self._file.tasks.append(task) self._onFileUpdated() def _tasks_list_taskModified(self, task): self._onFileUpdated() def _tasks_list_taskArchived(self, task): self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _archive_all_done_tasks(self): done = [task for task in self._file.tasks if task.is_complete] for task in done: self._file.saveDoneTask(task) self._file.tasks.remove(task) self._onFileUpdated() def _onFileUpdated(self): self._filters_tree_controller.showFilters(self._file, self._show_completed) self._task_editor_service.updateValues(self._file) self._setIsModified(True) self.auto_save() def _canExit(self): if not self._is_modified: return True button = self._dialogs.showSaveDiscardCancel('Unsaved changes...') if button == QtWidgets.QMessageBox.Save: self.save() return True else: return button == QtWidgets.QMessageBox.Discard def view_onCloseEvent(self, closeEvent): if self._canExit(): self._settings.setValue("show_toolbar", self._show_toolbar) if self.filterViewAction.isChecked(): # we only save size if it is visible self._settings.setValue("splitter_pos", self.view.centralWidget().sizes()) self._settings.setValue("current_filters", self._filters_tree_controller.view.getSelectedFilterNames()) self._settings.setValue("main_window_geometry", self.view.saveGeometry()) self._settings.setValue("main_window_state", self.view.saveState()) closeEvent.accept() else: closeEvent.ignore() def _setIsModified(self, is_modified): self._is_modified = is_modified self._updateTitle() self._menu_controller.saveAction.setEnabled(is_modified) self._menu_controller.revertAction.setEnabled(is_modified) def save(self): logger.debug('MainController.save called.') self._fileObserver.clear() filename = self._file.filename ok = True if not filename: (filename, ok) = \ QtWidgets.QFileDialog.getSaveFileName(self.view, filter=FILENAME_FILTERS) if ok and filename: self._file.save(filename) self._settings.setValue("last_open_file", filename) self._settings.sync() self._setIsModified(False) logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _updateTitle(self): title = 'QTodoTxt - ' if self._file.filename: filename = os.path.basename(self._file.filename) title += filename else: title += 'Untitled' if self._is_modified: title += ' (*)' self.view.setWindowTitle(title) def open(self): (filename, ok) = \ QtWidgets.QFileDialog.getOpenFileName(self.view, filter=FILENAME_FILTERS) if ok and filename: try: self.openFileByName(filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def new(self): if self._canExit(): self._file = File() self._loadFileToUI() def revert(self): if self._dialogs.showConfirm('Revert to saved file (and lose unsaved changes)?'): try: self.openFileByName(self._file.filename) except ErrorLoadingFile as ex: self._dialogs.showError(str(ex)) def openFileByName(self, filename): logger.debug('MainController.openFileByName called with filename="{}"'.format(filename)) self._fileObserver.clear() self._file.load(filename) self._loadFileToUI() self._settings.setValue("last_open_file", filename) self._settings.sync() logger.debug('Adding {} to watchlist'.format(filename)) self._fileObserver.addPath(self._file.filename) def _loadFileToUI(self): self._setIsModified(False) self._filters_tree_controller.showFilters(self._file, self._show_completed) self._task_editor_service.updateValues(self._file) def _updateView(self): self.view.restoreGeometry(self._settings.value("main_window_geometry", b"")) self.view.restoreState(self._settings.value("main_window_state", b"")) splitterPosition = self._settings.value("splitter_pos", (200, 400)) splitterPosition = [int(x) for x in splitterPosition] self.view.centralWidget().setSizes(splitterPosition) self._restoreShowCompleted() self._restoreFilterView() self._restoreShowFuture() def _restoreShowCompleted(self): val = int(self._settings.value("show_completed_tasks", 1)) if val: self._show_completed = True self.showCompletedAction.setChecked(True) else: self._show_completed = False self.showCompletedAction.setChecked(False) def updateFilters(self): self._onFilterSelectionChanged(self._filters_tree_controller.view.getSelectedFilters()) def toggleVisible(self): if self.view.isMinimized(): self.view.showNormal() self.view.activateWindow() else: self.view.showMinimized()