class TasksListController(QtCore.QObject): taskModified = QtCore.pyqtSignal(tasklib.Task) taskCreated = QtCore.pyqtSignal(tasklib.Task) taskArchived = QtCore.pyqtSignal(tasklib.Task) taskDeleted = QtCore.pyqtSignal(tasklib.Task) def __init__(self, view, task_editor_service): QtCore.QObject.__init__(self) self._view = view self._task_editor_service = task_editor_service self._task_htmlizer = TaskHtmlizer() self._view.taskActivated.connect(self.editTask) self._initCreateTaskAction() self._initEditTaskAction() self._initDeleteSelectedTasksAction() self._initCompleteSelectedTasksAction() self._initDecreasePrioritySelectedTasksAction() self._initIncreasePrioritySelectedTasksAction() def _initEditTaskAction(self): action = QtWidgets.QAction(getIcon('TaskEdit.png'), '&Edit Task', self) action.setShortcuts(['Ctrl+E']) action.triggered.connect(self.editTask) self._view.addListAction(action) self.editTaskAction = action def _initCreateTaskAction(self): action = QtWidgets.QAction(getIcon('TaskCreate.png'), '&Create New Task', self) action.setShortcuts(['Insert', 'Ctrl+I', 'Ctrl+N']) action.triggered.connect(self.createTask) self._view.addListAction(action) self.createTaskAction = action def _initDeleteSelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskDelete.png'), '&Delete Selected Tasks', self) action.setShortcut('Delete') action.triggered.connect(self._deleteSelectedTasks) self._view.addListAction(action) self.deleteSelectedTasksAction = action def _initCompleteSelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskComplete.png'), 'C&omplete Selected Tasks', self) action.setShortcuts(['x', 'c']) action.triggered.connect(self._completeSelectedTasks) self._view.addListAction(action) self.completeSelectedTasksAction = action def _initDecreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskPriorityDecrease.png'), 'Decrease Priority', self) action.setShortcuts(['-', '<']) action.triggered.connect(self._decreasePriority) self._view.addListAction(action) self.decreasePrioritySelectedTasksAction = action def _initIncreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskPriorityIncrease.png'), 'Increase Priority', self) action.setShortcuts(['+', '>']) action.triggered.connect(self._increasePriority) self._view.addListAction(action) self.increasePrioritySelectedTasksAction = action def completeTask(self, task): if not task.is_complete: task.setCompleted() else: task.setPending() if int(QtCore.QSettings().value("auto_archive", 1)): self.taskArchived.emit(task) else: self.taskModified.emit(task) def _completeSelectedTasks(self): tasks = self._view.getSelectedTasks() if tasks: confirm = int(QtCore.QSettings().value("confirm_complete", 1)) if not confirm or self._confirmTasksAction(tasks, 'Toggle Completeness of'): for task in tasks: self.completeTask(task) def _deleteSelectedTasks(self): tasks = self._view.getSelectedTasks() if tasks: if self._confirmTasksAction(tasks, 'Delete'): for task in tasks: self._view.removeTask(task) self.taskDeleted.emit(task) def _confirmTasksAction(self, tasks, messagePrefix): if len(tasks) == 1: message = '<b>%s the following task?</b><ul>' % messagePrefix else: message = '<b>%s the following tasks?</b><ul>' % messagePrefix for task in tasks: message += '<li>%s</li>' % self._task_htmlizer.task2html(task) message += '</ul>' result = QtWidgets.QMessageBox.question(self._view, 'Confirm', message, buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes ) return result == QtWidgets.QMessageBox.Yes def _decreasePriority(self): tasks = self._view.getSelectedTasks() if tasks: for task in tasks: task.decreasePriority() self._view.updateTask(task) self.taskModified.emit(task) def _increasePriority(self): tasks = self._view.getSelectedTasks() if tasks: for task in tasks: task.increasePriority() self._view.updateTask(task) self.taskModified.emit(task) def showTasks(self, tasks): previouslySelectedTasks = self._view.getSelectedTasks() self._view.clear() self._sortTasks(tasks) for task in tasks: self._view.addTask(task) self._reselect(previouslySelectedTasks) def _reselect(self, tasks): for task in tasks: self._view.selectTaskByText(task.text) def _sortTasks(self, tasks): tasks.sort(reverse=True) def _addCreationDate(self, text): date_string = date.today().strftime('%Y-%m-%d') if text[:3] in self._task_editor_service._priorities: text = '%s %s %s' % (text[:3], date_string, text[4:]) else: text = '%s %s' % (date_string, text) return text def createTask(self): (text, ok) = self._task_editor_service.createTask() if ok and text: if int(QtCore.QSettings().value("add_created_date", 1)): text = self._addCreationDate(text) task = tasklib.Task(text) self._view.addTask(task) self._view.clearSelection() self._view.selectTask(task) self.taskCreated.emit(task) def editTask(self, task=None): if not task: tasks = self._view.getSelectedTasks() # FIXME: instead of this we should disable icon when no task or serveral tasks are selected if len(tasks) == 0: print("No task selected") return elif len(tasks) > 1: print("More than one task selected") return task = tasks[0] (text, ok) = self._task_editor_service.editTask(task) if ok and text: if text != task.text: task.parseLine(text) self._view.updateTask(task) self.taskModified.emit(task)
class TasksListView(QtGui.QListWidget): taskActivated = QtCore.Signal(todolib.Task) def __init__(self, parent=None): super(TasksListView, self).__init__(parent) self._task_htmlizer = TaskHtmlizer() self._initUI() self._oldSelected = [] def addTask(self, task): item = TaskListWidgetItem(task, self) label = self._createLabel(task) self.setItemWidget(item, label) def addListAction(self, action): self.addAction(action) def _initUI(self): self.setSelectionMode( QtGui.QAbstractItemView.SelectionMode.ExtendedSelection) self.itemDoubleClicked.connect(self._list_itemActivated) self.itemSelectionChanged.connect(self._list_itemPressed) def _createLabel(self, task): label = QtGui.QLabel() label.setTextFormat(QtCore.Qt.RichText) label.setOpenExternalLinks(True) text = self._task_htmlizer.task2html(task) label.setText(text) return label def _findItemByTask(self, task): for index in range(self.count()): item = self.item(index) if item.task == task: return item return None def _findItemByTaskText(self, text): for index in range(self.count()): item = self.item(index) if item.task.text == text: return item return None def updateTask(self, task): item = self._findItemByTask(task) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def _selectItem(self, item): if item: item.setSelected(True) self.setCurrentItem(item) def selectTask(self, task): item = self._findItemByTask(task) self._selectItem(item) def selectTaskByText(self, text): item = self._findItemByTaskText(text) self._selectItem(item) def removeTask(self, task): item = self._findItemByTask(task) if item: self._oldSelected.remove(item) self.removeItemWidget(item) def _list_itemActivated(self, item): self.taskActivated.emit(item.task) def getSelectedTasks(self): items = self.selectedItems() return [item.task for item in items] def _list_itemPressed(self): for oldSelected in self._oldSelected: label = self.itemWidget(oldSelected) text = self._task_htmlizer.task2html(oldSelected.task) label.setText(text) self._oldSelected = [] items = self.selectedItems() for item in items: self._oldSelected.append(item) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def keyPressEvent(self, event): key = event.key() if key == QtCore.Qt.Key_Return: items = self.selectedItems() if len(items) > 0: self._list_itemActivated(items[-1]) else: QtGui.QListWidget.keyPressEvent(self, event) return
def toHtml(self): """ return a task as an html block which is a pretty display of a line in todo.txt format """ htmlizer = TaskHtmlizer() return htmlizer.task2html(self)
class TasksListView(QtGui.QWidget): taskActivated = QtCore.Signal(todolib.Task) def __init__(self,parent=None): super(TasksListView, self).__init__(parent) self._task_htmlizer = TaskHtmlizer() self._initUI() self._oldSelected = [] def clear(self): self._list.clear() def clearSelection(self): self._list.clearSelection() def addTask(self, task): item = TaskListWidgetItem(task, self._list) label = self._createLabel(task) self._list.setItemWidget(item, label) def addListAction(self, action): self._list.addAction(action) def _initUI(self): layout = QtGui.QGridLayout() self._list = QtGui.QListWidget(self) self._list.setSelectionMode( QtGui.QAbstractItemView.SelectionMode.ExtendedSelection) self._list.itemActivated.connect(self._list_itemActivated) self._list.itemSelectionChanged.connect(self._list_itemPressed) layout.addWidget(self._list) self.setLayout(layout) def _createLabel(self, task): label = QtGui.QLabel() label.setTextFormat(QtCore.Qt.RichText) label.setOpenExternalLinks(True) text = self._task_htmlizer.task2html(task) label.setText(text) return label def _findItemByTask(self, task): for index in range(self._list.count()): item = self._list.item(index) if item.task == task: return item return None def _findItemByTaskText(self, text): for index in range(self._list.count()): item = self._list.item(index) if item.task.text == text: return item return None def updateTask(self, task): item = self._findItemByTask(task) label = self._list.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def _selectItem(self, item): if item: item.setSelected(True) self._list.setCurrentItem(item) def selectTask(self, task): item = self._findItemByTask(task) self._selectItem(item) def selectTaskByText(self, text): item = self._findItemByTaskText(text) self._selectItem(item) def removeTask(self, task): item = self._findItemByTask(task) if item: self._list.removeItemWidget(item) self._list.takeItem(self._list.row(item)) def _list_itemActivated(self, item): self.taskActivated.emit(item.task) def getSelectedTasks(self): items = self._list.selectedItems() return [item.task for item in items] def _list_itemPressed(self): for oldSelected in self._oldSelected: label = self._list.itemWidget(oldSelected) text = self._task_htmlizer.task2html(oldSelected.task,False) label.setText(text) self._oldSelected = [] items = self._list.selectedItems() for item in items: self._oldSelected.append(item) label = self._list.itemWidget(item) text = self._task_htmlizer.task2html(item.task,True) label.setText(text)
class TasksListController(QtCore.QObject): taskModified = QtCore.pyqtSignal(tasklib.Task) taskCreated = QtCore.pyqtSignal(tasklib.Task) taskArchived = QtCore.pyqtSignal(tasklib.Task) taskDeleted = QtCore.pyqtSignal(tasklib.Task) def __init__(self, view, task_editor_service): QtCore.QObject.__init__(self) self.view = view self._task_editor_service = task_editor_service self._task_htmlizer = TaskHtmlizer() self.view.taskActivated.connect(self.editTask) self._initCreateTaskAction() self._initEditTaskAction() if int(QtCore.QSettings().value("show_delete", 0)): self._initDeleteSelectedTasksAction() self._initCompleteSelectedTasksAction() self._initDecreasePrioritySelectedTasksAction() self._initIncreasePrioritySelectedTasksAction() def _initEditTaskAction(self): action = QtWidgets.QAction(getIcon('TaskEdit.png'), '&Edit Task', self) action.setShortcuts(['Ctrl+E']) action.triggered.connect(self.editTask) self.view.addListAction(action) self.editTaskAction = action def _initCreateTaskAction(self): action = QtWidgets.QAction(getIcon('TaskCreate.png'), '&Create New Task', self) action.setShortcuts(['Insert', 'Ctrl+I', 'Ctrl+N']) action.triggered.connect(self.createTask) self.view.addListAction(action) self.createTaskAction = action def _initDeleteSelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskDelete.png'), '&Delete Selected Tasks', self) action.setShortcut('Delete') action.triggered.connect(self._deleteSelectedTasks) self.view.addListAction(action) self.deleteSelectedTasksAction = action def _initCompleteSelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskComplete.png'), 'C&omplete Selected Tasks', self) action.setShortcuts(['x', 'c']) action.triggered.connect(self._completeSelectedTasks) self.view.addListAction(action) self.completeSelectedTasksAction = action def _initDecreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskPriorityDecrease.png'), 'Decrease Priority', self) action.setShortcuts(['-', '<']) action.triggered.connect(self._decreasePriority) self.view.addListAction(action) self.decreasePrioritySelectedTasksAction = action def _initIncreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction(getIcon('TaskPriorityIncrease.png'), 'Increase Priority', self) action.setShortcuts(['+', '>']) action.triggered.connect(self._increasePriority) self.view.addListAction(action) self.increasePrioritySelectedTasksAction = action def completeTask(self, task): if not task.is_complete: task.setCompleted() else: task.setPending() if int(QtCore.QSettings().value("auto_archive", 0)): self.taskArchived.emit(task) else: self.taskModified.emit(task) def _completeSelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: confirm = int(QtCore.QSettings().value("confirm_complete", 1)) if not confirm or self._confirmTasksAction( tasks, 'Toggle Completeness of'): for task in tasks: self.completeTask(task) def _deleteSelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: if self._confirmTasksAction(tasks, 'Delete'): for task in tasks: self.view.removeTask(task) self.taskDeleted.emit(task) def _confirmTasksAction(self, tasks, messagePrefix): if len(tasks) == 1: message = '<b>%s the following task?</b><ul>' % messagePrefix else: message = '<b>%s the following tasks?</b><ul>' % messagePrefix for task in tasks: message += '<li>%s</li>' % self._task_htmlizer.task2html(task) message += '</ul>' result = QtWidgets.QMessageBox.question( self.view, 'Confirm', message, buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes) return result == QtWidgets.QMessageBox.Yes def _decreasePriority(self): tasks = self.view.getSelectedTasks() if tasks: for task in tasks: task.decreasePriority() self.view.updateTask(task) self.taskModified.emit(task) def _increasePriority(self): tasks = self.view.getSelectedTasks() if tasks: for task in tasks: task.increasePriority() self.view.updateTask(task) self.taskModified.emit(task) def showTasks(self, tasks): previouslySelectedTasks = self.view.getSelectedTasks() self.view.clear() self._sortTasks(tasks) for task in tasks: self.view.addTask(task) self._reselect(previouslySelectedTasks) def _reselect(self, tasks): for task in tasks: self.view.selectTaskByText(task.text) def _sortTasks(self, tasks): tasks.sort(reverse=True) def _addCreationDate(self, text): date_string = date.today().strftime('%Y-%m-%d') if text[:3] in self._task_editor_service._priorities: text = '%s %s %s' % (text[:3], date_string, text[4:]) else: text = '%s %s' % (date_string, text) return text def createTask(self): (text, ok) = self._task_editor_service.createTask() if ok and text: if int(QtCore.QSettings().value("add_created_date", 0)): text = self._addCreationDate(text) task = tasklib.Task(text) self.view.addTask(task) self.view.clearSelection() self.view.selectTask(task) self.taskCreated.emit(task) def editTask(self, task=None): if not task: tasks = self.view.getSelectedTasks() # FIXME: instead of this we should disable icon when no task or serveral tasks are selected if len(tasks) == 0: print("No task selected") return elif len(tasks) > 1: print("More than one task selected") return task = tasks[0] (text, ok) = self._task_editor_service.editTask(task) if ok and text: if text != task.text: task.parseLine(text) self.view.updateTask(task) self.taskModified.emit(task)
class TasksListController(QtCore.QObject): taskModified = QtCore.pyqtSignal(tasklib.Task) taskCreated = QtCore.pyqtSignal(tasklib.Task) taskArchived = QtCore.pyqtSignal(tasklib.Task) taskDeleted = QtCore.pyqtSignal(tasklib.Task) def __init__(self, view, mfile): QtCore.QObject.__init__(self) self.style = ":/white_icons" if str(QtCore.QSettings().value("color_schem", "")).find("dark") >= 0: self.style = ":/dark_icons" self._settings = QtCore.QSettings() self.view = view self.view.setFileObject(mfile) self._task_htmlizer = TaskHtmlizer() self._task_editor_service = TaskEditor(self.view, mfile) self.view.taskActivated.connect(self.editTask) self.view.currentTaskChanged.connect(self.updateActions) self.view.taskDeleted.connect(self.taskDeleted.emit) self.view.itemSelectionChanged.connect(self.updateActions) self._initCreateTaskAction() self._initEditTaskAction() self._initCopySelectedTasksAction() if int(QtCore.QSettings().value("show_delete", 1)): self._initDeleteSelectedTasksAction() self._initCompleteSelectedTasksAction() self._initDecreasePrioritySelectedTasksAction() self._initIncreasePrioritySelectedTasksAction() self._initCreateTaskActionOnTemplate() self._initAddLinkAction() self.view.taskCreated.connect(self._task_created) self.view.taskModified.connect(self._task_modified) self.disableTaskActions() def _task_created(self, task): self.view.clearSelection() self.view.selectTask(task) self.taskCreated.emit(task) def _task_modified(self, task): self.taskModified.emit(task) def _initEditTaskAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskEdit.png'), self.tr('&Edit Task'), self) action.setShortcuts(['Ctrl+E', 'Enter']) action.setDisabled(True) action.triggered.connect(self.editTask) self.view.addAction(action) self.editTaskAction = action def _initCreateTaskAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskCreate.png'), self.tr('&Create new task'), self) action.setShortcuts(['Insert', 'Ctrl+I', 'Ctrl+N']) action.triggered.connect(self.createTask) self.view.addAction(action) self.createTaskAction = action def _initCreateTaskActionOnTemplate(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskAddOnTem.png'), self.tr('&Create a new task based on current task'), self) action.setShortcuts(['Shift+Insert', 'Ctrl+Shift+I']) action.triggered.connect(self.createTaskOnTemplate) self.view.addAction(action) self.createTaskActionOnTemplate = action def _initCopySelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskCopy.png'), self.tr('Copy selected tasks'), self) action.setShortcuts([QtGui.QKeySequence.Copy]) action.triggered.connect(self._copySelectedTasks) self.view.addAction(action) self.copySelectedTasksAction = action def _initDeleteSelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskDelete.png'), self.tr('&Delete selected tasks'), self) action.setShortcut('Delete') action.triggered.connect(self._deleteSelectedTasks) self.view.addAction(action) self.deleteSelectedTasksAction = action def _initCompleteSelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskComplete.png'), self.tr('C&omplete selected tasks'), self) action.setShortcuts(['x', 'c']) action.triggered.connect(self._completeSelectedTasks) self.view.addAction(action) self.completeSelectedTasksAction = action def _initDecreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskPriorityDecrease.png'), self.tr('Decrease priority'), self) action.setShortcuts(['-', '<']) action.triggered.connect(self._decreasePriority) self.view.addAction(action) self.decreasePrioritySelectedTasksAction = action def _initIncreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskPriorityIncrease.png'), self.tr('Increase priority'), self) action.setShortcuts(['+', '>']) action.triggered.connect(self._increasePriority) self.view.addAction(action) self.increasePrioritySelectedTasksAction = action def _initAddLinkAction(self): self.addLinkAction = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/link.png'), self.tr('Add &Link to file'), self) self.addLinkAction.setShortcuts(['Ctrl+Shift+L']) self.view.addAction(self.addLinkAction) self.addLinkAction.triggered.connect(self._addLink) def _addLink(self): tasks = self.view.getSelectedTasks() if tasks: uris = LinkDialog.getLink(self.view, directory=".") for uri in uris: for task in tasks: task.text = task.text + " " + uri self.taskModified.emit(task) @property def _useTaskDialog(self): return int(self._settings.value("use_task_dialog", 0)) def completeTask(self, task): if not task.is_complete: # Check if task is recurrent and has a due date if task.recursion is not None and task.due is not None: self._recurTask(task) task.setCompleted() else: task.setPending() if int(QtCore.QSettings().value("auto_archive", 0)): self.taskArchived.emit(task) else: self.taskModified.emit(task) def _recurTask(self, task): if task.recursion.interval == 'd': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta( days=int(task.recursion.increment)) else: next_due_date = date.today() + timedelta( days=int(task.recursion.increment)) elif task.recursion.interval == 'b': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = self._incrWorkDays( task.due, int(task.recursion.increment)) else: next_due_date = self._incrWorkDays( date.today(), int(task.recursion.increment)) elif task.recursion.interval == 'w': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta( weeks=int(task.recursion.increment)) else: next_due_date = date.today() + timedelta( weeks=int(task.recursion.increment)) elif task.recursion.interval == 'm': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta(weeks=int( task.recursion.increment) * 4) # 4 weeks in a month else: next_due_date = date.today() + timedelta( weeks=int(task.recursion.increment) * 4) # 4 weeks in a month elif task.recursion.interval == 'y': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta(weeks=int( task.recursion.increment) * 52) # 52 weeks in a year else: next_due_date = date.today() + timedelta( weeks=int(task.recursion.increment) * 52) # 52 weeks in a year else: # Test already made during line parsing - shouldn't be a problem here pass # Set new due date in old task text rec_text = task.updateDateInTask(task.text, next_due_date) # create a new task duplicate return self.createTask(rec_text) def _incrWorkDays(self, startDate, daysToIncrement): while daysToIncrement > 0: if startDate.weekday() == 4: # Friday startDate = startDate + timedelta(days=3) elif startDate.weekday() == 5: # Saturday startDate = startDate + timedelta(days=2) else: startDate = startDate + timedelta(days=1) daysToIncrement -= 1 return startDate def _completeSelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: confirm = int(QtCore.QSettings().value("confirm_complete", 1)) if not confirm or self._confirmTasksAction( tasks, self.tr('Toggle completeness of')): for task in tasks: self.completeTask(task) def _deleteSelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: if self._confirmTasksAction(tasks, self.tr('Delete')): for task in tasks: self.view.removeTask(task) self.taskDeleted.emit(task) def _confirmTasksAction(self, tasks, messagePrefix): if len(tasks) == 1: message = self.tr( '<b>%s the following task?</b><ul>') % messagePrefix else: message = self.tr( '<b>%s the following tasks?</b><ul>') % messagePrefix for task in tasks: message += '<li>%s</li>' % self._task_htmlizer.task2html(task) message += '</ul>' result = QtWidgets.QMessageBox.question( self.view, self.tr('Confirm'), message, buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes) return result == QtWidgets.QMessageBox.Yes def _decreasePriority(self): tasks = self.view.getSelectedTasks() if tasks: for task in tasks: task.decreasePriority() self.taskModified.emit(task) def _increasePriority(self): tasks = self.view.getSelectedTasks() if tasks: for task in tasks: task.increasePriority() self.taskModified.emit(task) def showTasks(self, tasks): previouslySelectedTasks = self.view.getSelectedTasks() self.view.clear() self._sortTasks(tasks) for task in tasks: self.view.addTask(task) self._reselect(previouslySelectedTasks) def _reselect(self, tasks): for task in tasks: self.view.selectTaskByText(task.text) def _sortTasks(self, tasks): tasks.sort(reverse=True) def _removeCreationDate(self, text): match = re.match(r'^(\([A-Z]\)\s)?[0-9]{4}\-[0-9]{2}\-[0-9]{2}\s(.*)', text) if match: if match.group(1): text = match.group(1) + match.group(2) else: text = match.group(2) return text def _addCreationDate(self, text): date_string = date.today().strftime('%Y-%m-%d') if text[:3] in self._task_editor_service.priorities: text = '%s %s %s' % (text[:3], date_string, text[4:]) else: text = '%s %s' % (date_string, text) return text def _createTask(self, text): if int(QtCore.QSettings().value("add_created_date", 0)): text = self._removeCreationDate(text) text = self._addCreationDate(text) task = tasklib.Task(text) self.view.addTask(task) self._task_created(task) return task def createTask(self, task=None): if not self._useTaskDialog: self.view.createTask(task) return (text, ok) = self._task_editor_service.createTask(task) if ok and text: task = self._createTask(text) return task def createTaskOnTemplate(self): tasks = self.view.getSelectedTasks() if len(tasks) != 1: return task = tasks[0] return self.createTask(task) def editTask(self, task=None): if not self._useTaskDialog: self.view.editCurrentTask() return if not task: tasks = self.view.getSelectedTasks() task = tasks[0] (text, ok) = self._task_editor_service.editTask(task) if ok and text: task.text = text def _copySelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: text = "".join(str(task) + os.linesep for task in tasks) app = QtWidgets.QApplication.instance() app.clipboard().setText(text) def updateActions(self): tasks = self.view.selectedItems() if tasks: self.enableTaskActions() if len(tasks) > 1: self.editTaskAction.setEnabled(False) self.addLinkAction.setEnabled(False) self.createTaskActionOnTemplate.setEnabled(False) else: self.disableTaskActions() def enableTaskActions(self): self.editTaskAction.setEnabled(True) self.addLinkAction.setEnabled(True) self.createTaskActionOnTemplate.setEnabled(True) self.deleteSelectedTasksAction.setEnabled(True) self.completeSelectedTasksAction.setEnabled(True) self.copySelectedTasksAction.setEnabled(True) self.increasePrioritySelectedTasksAction.setEnabled(True) self.decreasePrioritySelectedTasksAction.setEnabled(True) def disableTaskActions(self): self.editTaskAction.setEnabled(False) self.addLinkAction.setEnabled(False) self.createTaskActionOnTemplate.setEnabled(False) self.deleteSelectedTasksAction.setEnabled(False) self.completeSelectedTasksAction.setEnabled(False) self.copySelectedTasksAction.setEnabled(False) self.increasePrioritySelectedTasksAction.setEnabled(False) self.decreasePrioritySelectedTasksAction.setEnabled(False)
def toHtml(self): """ return a task as an html block which is a pretty display of a line in todo.txt format """ htmlizer = TaskHtmlizer() return htmlizer.task2html(self)
class TasksListView(QtWidgets.QListWidget): taskActivated = QtCore.pyqtSignal(tasklib.Task) def __init__(self, parent=None): super(TasksListView, self).__init__(parent) self.setLayoutMode(self.Batched) self.setAlternatingRowColors(True) self._task_htmlizer = TaskHtmlizer() self._initUI() self._oldSelected = [] def addTask(self, task): item = TaskListWidgetItem(task, self) label = self._createLabel(task) label.setWordWrap(True) # set minimum width to a reasonable value to get a useful # sizeHint _height_ when using word wrap label.setMinimumWidth(self.width() - 20) # set items size and add some space between items item.setSizeHint(QtCore.QSize(label.sizeHint().width(), label.sizeHint().height() + 5)) self.setItemWidget(item, label) def addListAction(self, action): self.addAction(action) def _initUI(self): self.setSelectionMode( QtWidgets.QAbstractItemView.ExtendedSelection) self.itemDoubleClicked.connect(self._list_itemActivated) self.itemSelectionChanged.connect(self._list_itemPressed) def _createLabel(self, task): label = QtWidgets.QLabel() label.setTextFormat(QtCore.Qt.RichText) label.setOpenExternalLinks(True) text = self._task_htmlizer.task2html(task) label.setText(text) return label def _findItemByTask(self, task): for index in range(self.count()): item = self.item(index) if item.task == task: return item return None def _findItemByTaskText(self, text): for index in range(self.count()): item = self.item(index) if item.task.text == text: return item return None def updateTask(self, task): item = self._findItemByTask(task) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def _selectItem(self, item): if item: item.setSelected(True) self.setCurrentItem(item) def selectTask(self, task): item = self._findItemByTask(task) self._selectItem(item) def selectTaskByText(self, text): item = self._findItemByTaskText(text) self._selectItem(item) def removeTask(self, task): item = self._findItemByTask(task) if item: self._oldSelected.remove(item) self.removeItemWidget(item) def _list_itemActivated(self, item): self.taskActivated.emit(item.task) def getSelectedTasks(self): items = self.selectedItems() return [item.task for item in items] def _list_itemPressed(self): for oldSelected in self._oldSelected: label = self.itemWidget(oldSelected) text = self._task_htmlizer.task2html(oldSelected.task) label.setText(text) self._oldSelected = [] items = self.selectedItems() for item in items: self._oldSelected.append(item) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def keyPressEvent(self, event): key = event.key() if key == QtCore.Qt.Key_Return: items = self.selectedItems() if len(items) > 0: self._list_itemActivated(items[-1]) else: QtWidgets.QListWidget.keyPressEvent(self, event) return
class TasksListView(QtGui.QListWidget): taskActivated = QtCore.Signal(tasklib.Task) def __init__(self, parent=None): super(TasksListView, self).__init__(parent) self.setLayoutMode(self.LayoutMode.Batched) self.setAlternatingRowColors(True) self._task_htmlizer = TaskHtmlizer() self._initUI() self._oldSelected = [] def addTask(self, task): item = TaskListWidgetItem(task, self) label = self._createLabel(task) label.setWordWrap(True) # set minimum width to a reasonable value to get a useful # sizeHint _height_ when using word wrap label.setMinimumWidth(self.width() - 20) # set items size and add some space between items item.setSizeHint( QtCore.QSize(label.sizeHint().width(), label.sizeHint().height() + 5)) self.setItemWidget(item, label) def addListAction(self, action): self.addAction(action) def _initUI(self): self.setSelectionMode( QtGui.QAbstractItemView.SelectionMode.ExtendedSelection) self.itemDoubleClicked.connect(self._list_itemActivated) self.itemSelectionChanged.connect(self._list_itemPressed) def _createLabel(self, task): label = QtGui.QLabel() label.setTextFormat(QtCore.Qt.RichText) label.setOpenExternalLinks(True) text = self._task_htmlizer.task2html(task) label.setText(text) return label def _findItemByTask(self, task): for index in range(self.count()): item = self.item(index) if item.task == task: return item return None def _findItemByTaskText(self, text): for index in range(self.count()): item = self.item(index) if item.task.text == text: return item return None def updateTask(self, task): item = self._findItemByTask(task) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def _selectItem(self, item): if item: item.setSelected(True) self.setCurrentItem(item) def selectTask(self, task): item = self._findItemByTask(task) self._selectItem(item) def selectTaskByText(self, text): item = self._findItemByTaskText(text) self._selectItem(item) def removeTask(self, task): item = self._findItemByTask(task) if item: self._oldSelected.remove(item) self.removeItemWidget(item) def _list_itemActivated(self, item): self.taskActivated.emit(item.task) def getSelectedTasks(self): items = self.selectedItems() return [item.task for item in items] def _list_itemPressed(self): for oldSelected in self._oldSelected: label = self.itemWidget(oldSelected) text = self._task_htmlizer.task2html(oldSelected.task) label.setText(text) self._oldSelected = [] items = self.selectedItems() for item in items: self._oldSelected.append(item) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def keyPressEvent(self, event): key = event.key() if key == QtCore.Qt.Key_Return: items = self.selectedItems() if len(items) > 0: self._list_itemActivated(items[-1]) else: QtGui.QListWidget.keyPressEvent(self, event) return
class TasksListView(QtGui.QListWidget): taskActivated = QtCore.Signal(todolib.Task) def __init__(self, parent=None): super(TasksListView, self).__init__(parent) self._task_htmlizer = TaskHtmlizer() self._initUI() self._oldSelected = [] def addTask(self, task): item = TaskListWidgetItem(task, self) label = self._createLabel(task) self.setItemWidget(item, label) def addListAction(self, action): self.addAction(action) def _initUI(self): self.setSelectionMode( QtGui.QAbstractItemView.SelectionMode.ExtendedSelection) self.itemDoubleClicked.connect(self._list_itemActivated) self.itemSelectionChanged.connect(self._list_itemPressed) def _createLabel(self, task): label = QtGui.QLabel() label.setTextFormat(QtCore.Qt.RichText) label.setOpenExternalLinks(True) text = self._task_htmlizer.task2html(task) label.setText(text) return label def _findItemByTask(self, task): for index in range(self.count()): item = self.item(index) if item.task == task: return item return None def _findItemByTaskText(self, text): for index in range(self.count()): item = self.item(index) if item.task.text == text: return item return None def updateTask(self, task): item = self._findItemByTask(task) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task) label.setText(text) def _selectItem(self, item): if item: item.setSelected(True) self.setCurrentItem(item) def selectTask(self, task): item = self._findItemByTask(task) self._selectItem(item) def selectTaskByText(self, text): item = self._findItemByTaskText(text) self._selectItem(item) def removeTask(self, task): item = self._findItemByTask(task) if item: self._oldSelected.remove(item) self.removeItemWidget(item) def _list_itemActivated(self, item): self.taskActivated.emit(item.task) def getSelectedTasks(self): items = self.selectedItems() return [item.task for item in items] def _list_itemPressed(self): for oldSelected in self._oldSelected: label = self.itemWidget(oldSelected) text = self._task_htmlizer.task2html(oldSelected.task, False) label.setText(text) self._oldSelected = [] items = self.selectedItems() for item in items: self._oldSelected.append(item) label = self.itemWidget(item) text = self._task_htmlizer.task2html(item.task, True) label.setText(text) def keyPressEvent(self, event): key = event.key() if key == QtCore.Qt.Key_Return: items = self.selectedItems() if len(items) > 0: self._list_itemActivated(items[-1]) else: QtGui.QListWidget.keyPressEvent(self, event) return
class TasksListController(QtCore.QObject): taskModified = QtCore.pyqtSignal(tasklib.Task) taskCreated = QtCore.pyqtSignal(tasklib.Task) taskArchived = QtCore.pyqtSignal(tasklib.Task) taskDeleted = QtCore.pyqtSignal(tasklib.Task) def __init__(self, view, mfile): QtCore.QObject.__init__(self) self.style = ":/white_icons" if str(QtCore.QSettings().value("color_schem", "")).find("dark") >= 0: self.style = ":/dark_icons" self._settings = QtCore.QSettings() self.view = view self.view.setFileObject(mfile) self._task_htmlizer = TaskHtmlizer() self._priorities = ["(" + i + ")" for i in string.ascii_uppercase] # FIXME: why do we have this? self.view.taskActivated.connect(self.view.editCurrentTask) self.view.currentTaskChanged.connect(self.updateActions) self.view.taskDeleted.connect(self.taskDeleted.emit) self.view.itemSelectionChanged.connect(self.updateActions) self._initCreateTaskAction() self._initEditTaskAction() self._initCopySelectedTasksAction() if int(QtCore.QSettings().value("show_delete", 1)): self._initDeleteSelectedTasksAction() self._initCompleteSelectedTasksAction() self._initDecreasePrioritySelectedTasksAction() self._initIncreasePrioritySelectedTasksAction() self._initCreateTaskActionOnTemplate() self._initAddLinkAction() self.view.taskCreated.connect(self._task_created) self.view.taskModified.connect(self._task_modified) self.disableTaskActions() def _task_created(self, task): self.view.clearSelection() self.view.selectTask(task) self.taskCreated.emit(task) def _task_modified(self, task): self.taskModified.emit(task) def _initEditTaskAction(self): action = QtWidgets.QAction(QtGui.QIcon(self.style + '/resources/TaskEdit.png'), self.tr('&Edit Task'), self) action.setShortcuts(['Ctrl+E', 'Enter']) action.setDisabled(True) action.triggered.connect(self.view.editCurrentTask) self.view.addAction(action) self.editTaskAction = action def _initCreateTaskAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskCreate.png'), self.tr('&Create new task'), self) action.setShortcuts(['Insert', 'Ctrl+I', 'Ctrl+N']) action.triggered.connect(self.view.createTask) self.view.addAction(action) self.createTaskAction = action def _initCreateTaskActionOnTemplate(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskAddOnTem.png'), self.tr('&Create a new task based on current task'), self) action.setShortcuts(['Shift+Insert', 'Ctrl+Shift+I']) action.triggered.connect(self.createTaskOnTemplate) self.view.addAction(action) self.createTaskActionOnTemplate = action def _initCopySelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskCopy.png'), self.tr('Copy selected tasks'), self) action.setShortcuts([QtGui.QKeySequence.Copy]) action.triggered.connect(self._copySelectedTasks) self.view.addAction(action) self.copySelectedTasksAction = action def _initDeleteSelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskDelete.png'), self.tr('&Delete selected tasks'), self) action.setShortcut('Delete') action.triggered.connect(self._deleteSelectedTasks) self.view.addAction(action) self.deleteSelectedTasksAction = action def _initCompleteSelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskComplete.png'), self.tr('C&omplete selected tasks'), self) action.setShortcuts(['x', 'c']) action.triggered.connect(self._completeSelectedTasks) self.view.addAction(action) self.completeSelectedTasksAction = action def _initDecreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskPriorityDecrease.png'), self.tr('Decrease priority'), self) action.setShortcuts(['-', '<']) action.triggered.connect(self._decreasePriority) self.view.addAction(action) self.decreasePrioritySelectedTasksAction = action def _initIncreasePrioritySelectedTasksAction(self): action = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/TaskPriorityIncrease.png'), self.tr('Increase priority'), self) action.setShortcuts(['+', '>']) action.triggered.connect(self._increasePriority) self.view.addAction(action) self.increasePrioritySelectedTasksAction = action def _initAddLinkAction(self): self.addLinkAction = QtWidgets.QAction( QtGui.QIcon(self.style + '/resources/link.png'), self.tr('Add &Link to file'), self) self.addLinkAction.setShortcuts(['Ctrl+Shift+L']) self.view.addAction(self.addLinkAction) self.addLinkAction.triggered.connect(self._addLink) def _addLink(self): tasks = self.view.getSelectedTasks() if tasks: uris = LinkDialog.getLink(self.view, directory=".") if uris: for uri in uris: for task in tasks: task.text = task.text + " " + uri self.taskModified.emit(task) def completeTask(self, task): if not task.is_complete: # Check if task is recurrent and has a due date if task.recursion is not None and task.due is not None: self._recurTask(task) task.setCompleted() # maybe we should not do that is show_completed is True.... self.view.selectNext() else: task.setPending() if int(QtCore.QSettings().value("auto_archive", 0)): self.taskArchived.emit(task) else: self.taskModified.emit(task) def _recurTask(self, task): if task.recursion.interval == 'd': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta(days=int(task.recursion.increment)) else: next_due_date = date.today() + timedelta(days=int(task.recursion.increment)) elif task.recursion.interval == 'b': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = self._incrWorkDays(task.due, int(task.recursion.increment)) else: next_due_date = self._incrWorkDays(date.today(), int(task.recursion.increment)) elif task.recursion.interval == 'w': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta(weeks=int(task.recursion.increment)) else: next_due_date = date.today() + timedelta(weeks=int(task.recursion.increment)) elif task.recursion.interval == 'm': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta(weeks=int(task.recursion.increment) * 4) # 4 weeks in a month else: next_due_date = date.today() + timedelta(weeks=int(task.recursion.increment) * 4) # 4 weeks in a month elif task.recursion.interval == 'y': if task.recursion.mode == recursiveMode.originalDueDate: next_due_date = task.due + timedelta(weeks=int(task.recursion.increment) * 52) # 52 weeks in a year else: next_due_date = date.today() + timedelta(weeks=int(task.recursion.increment) * 52) # 52 weeks in a year else: # Test already made during line parsing - shouldn't be a problem here pass # Set new due date in old task text rec_text = task.updateDateInTask(task.text, next_due_date) # create a new task duplicate self._createTask(rec_text) return def _incrWorkDays(self, startDate, daysToIncrement): while daysToIncrement > 0: if startDate.weekday() == 4: # Friday startDate = startDate + timedelta(days=3) elif startDate.weekday() == 5: # Saturday startDate = startDate + timedelta(days=2) else: startDate = startDate + timedelta(days=1) daysToIncrement -= 1 return startDate def _completeSelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: confirm = int(QtCore.QSettings().value("confirm_complete", 1)) if not confirm or self._confirmTasksAction(tasks, self.tr('Toggle completeness of')): for task in tasks: self.completeTask(task) def _deleteSelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: if self._confirmTasksAction(tasks, self.tr('Delete')): for task in tasks: self.view.removeTask(task) self.taskDeleted.emit(task) self.view.selectNext() def _confirmTasksAction(self, tasks, messagePrefix): if len(tasks) == 1: message = self.tr('<b>%s the following task?</b><ul>') % messagePrefix else: message = self.tr('<b>%s the following tasks?</b><ul>') % messagePrefix for task in tasks: message += '<li>%s</li>' % self._task_htmlizer.task2html(task) message += '</ul>' result = QtWidgets.QMessageBox.question( self.view, self.tr('Confirm'), message, buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes) return result == QtWidgets.QMessageBox.Yes def _decreasePriority(self): tasks = self.view.getSelectedTasks() if tasks: for task in tasks: task.decreasePriority() self.taskModified.emit(task) def _increasePriority(self): tasks = self.view.getSelectedTasks() if tasks: for task in tasks: task.increasePriority() self.taskModified.emit(task) def showTasks(self, tasks): previouslySelectedTasks = self.view.getSelectedTasks() self.view.clear() self._sortTasks(tasks) for task in tasks: self.view.addTask(task) self._reselect(previouslySelectedTasks) def _reselect(self, tasks): for task in tasks: self.view.selectTaskByText(task.text) def _sortTasks(self, tasks): tasks.sort(reverse=True) def _removeCreationDate(self, text): match = re.match(r'^(\([A-Z]\)\s)?[0-9]{4}\-[0-9]{2}\-[0-9]{2}\s(.*)', text) if match: if match.group(1): text = match.group(1) + match.group(2) else: text = match.group(2) return text def _addCreationDate(self, text): date_string = date.today().strftime('%Y-%m-%d') if text[:3] in self._priorities: text = '%s %s %s' % (text[:3], date_string, text[4:]) else: text = '%s %s' % (date_string, text) return text def _createTask(self, text): if int(QtCore.QSettings().value("add_created_date", 0)): text = self._removeCreationDate(text) text = self._addCreationDate(text) task = tasklib.Task(text) self.view.addTask(task) self._task_created(task) return task def createTaskOnTemplate(self): tasks = self.view.getSelectedTasks() if len(tasks) != 1: return task = tasks[0] return self.view.createTask(task) def _copySelectedTasks(self): tasks = self.view.getSelectedTasks() if tasks: text = "".join(str(task) + os.linesep for task in tasks) app = QtWidgets.QApplication.instance() app.clipboard().setText(text) def updateActions(self): tasks = self.view.selectedItems() if tasks: self.enableTaskActions() if len(tasks) > 1: self.editTaskAction.setEnabled(False) self.addLinkAction.setEnabled(False) self.createTaskActionOnTemplate.setEnabled(False) else: self.disableTaskActions() def enableTaskActions(self): self.editTaskAction.setEnabled(True) self.addLinkAction.setEnabled(True) self.createTaskActionOnTemplate.setEnabled(True) self.deleteSelectedTasksAction.setEnabled(True) self.completeSelectedTasksAction.setEnabled(True) self.copySelectedTasksAction.setEnabled(True) self.increasePrioritySelectedTasksAction.setEnabled(True) self.decreasePrioritySelectedTasksAction.setEnabled(True) def disableTaskActions(self): self.editTaskAction.setEnabled(False) self.addLinkAction.setEnabled(False) self.createTaskActionOnTemplate.setEnabled(False) self.deleteSelectedTasksAction.setEnabled(False) self.completeSelectedTasksAction.setEnabled(False) self.copySelectedTasksAction.setEnabled(False) self.increasePrioritySelectedTasksAction.setEnabled(False) self.decreasePrioritySelectedTasksAction.setEnabled(False)