diff options
author | Joris | 2020-06-06 17:44:26 +0200 |
---|---|---|
committer | Joris | 2020-06-06 19:54:03 +0200 |
commit | 1595e0de940a86a7810df0e02e43838d97c0d846 (patch) | |
tree | 9701eeec0d98baa9f6044b1911df68e4c8539819 /todo/gui/tags/panel/table | |
parent | 6b9195000eb5404c247288b384d7ca2bacc1ab23 (diff) | |
download | todo-1595e0de940a86a7810df0e02e43838d97c0d846.tar.gz todo-1595e0de940a86a7810df0e02e43838d97c0d846.tar.bz2 todo-1595e0de940a86a7810df0e02e43838d97c0d846.zip |
Provide nix build
Diffstat (limited to 'todo/gui/tags/panel/table')
-rw-r--r-- | todo/gui/tags/panel/table/__init__.py | 0 | ||||
-rw-r--r-- | todo/gui/tags/panel/table/menu.py | 35 | ||||
-rw-r--r-- | todo/gui/tags/panel/table/model.py | 103 | ||||
-rw-r--r-- | todo/gui/tags/panel/table/widget.py | 73 |
4 files changed, 211 insertions, 0 deletions
diff --git a/todo/gui/tags/panel/table/__init__.py b/todo/gui/tags/panel/table/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/todo/gui/tags/panel/table/__init__.py diff --git a/todo/gui/tags/panel/table/menu.py b/todo/gui/tags/panel/table/menu.py new file mode 100644 index 0000000..e286051 --- /dev/null +++ b/todo/gui/tags/panel/table/menu.py @@ -0,0 +1,35 @@ +from PyQt5 import QtWidgets, QtCore + +from todo.model.tag import Tag, ValidTagForm +import todo.database +import todo.db.task_tags +import todo.gui.tags.panel.dialog + +def open(table, update_tag_signal, position): + rows = set([index.row() for index in table.selectedIndexes()]) + + menu = QtWidgets.QMenu(table) + + actions = 0 + + if len(rows) == 1: + modify_action = menu.addAction(todo.gui.icon.dialog_open(menu.style()), "modify") + actions += 1 + else: + modify_action = QtWidgets.QAction(menu) + + tags = table.model().row_ids(rows) + if not todo.db.task_tags.one_is_used(todo.database.cursor(), tags): + delete_action = menu.addAction(todo.gui.icon.trash(menu.style()), "delete") + actions += 1 + else: + delete_action = QtWidgets.QAction(menu) + + if actions > 0: + action = menu.exec_(table.mapToGlobal(position + QtCore.QPoint(15, 20))) + if action == modify_action and len(rows) == 1: + row = list(rows)[0] + tag = table.model().get_at(row) + todo.gui.tags.panel.dialog.update(table, update_tag_signal, row, tag).exec_() + elif action == delete_action: + todo.gui.tags.panel.dialog.show_delete(table, rows) diff --git a/todo/gui/tags/panel/table/model.py b/todo/gui/tags/panel/table/model.py new file mode 100644 index 0000000..6f9d71a --- /dev/null +++ b/todo/gui/tags/panel/table/model.py @@ -0,0 +1,103 @@ +from PyQt5 import QtCore, QtWidgets, QtGui +from PyQt5.QtCore import Qt +from typing import List +import time +import math + +from todo.model.tag import Tag +import todo.util.array +import todo.util.range + +columns = 1 + +headers = ["Name", "Color"] + +default_sort = (0, Qt.AscendingOrder) + +class TableModel(QtCore.QAbstractTableModel): + def __init__(self, tags): + super(TableModel, self).__init__() + self._tags = tags + + def headerData(self, section, orientation, role): + if role == Qt.DisplayRole and orientation == Qt.Horizontal: + return headers[section] + elif role == Qt.DisplayRole and orientation == Qt.Vertical: + return section + 1 + else: + return QtCore.QVariant() + + def data(self, index, role): + tag = self._tags[index.row()] + + if role == Qt.DisplayRole: + if index.column() == 0: + return tag.name + elif index.column() == 1: + return tag.color + elif role == Qt.BackgroundRole: + return QtGui.QBrush(QtGui.QColor(tag.color)) + else: + return QtCore.QVariant() + + def rowCount(self, index): + return len(self._tags) + + def columnCount(self, index): + return columns + + def get_at(self, row): + if row >= 0 and row < len(self._tags): + return self._tags[row] + + def insert_tag(self, header: QtWidgets.QHeaderView, tag: Tag) -> int: + at = self.insert_position(header, tag) + self.beginInsertRows(QtCore.QModelIndex(), at, at) + self._tags.insert(at, tag) + self.endInsertRows() + return at + + def insert_position(self, header: QtWidgets.QHeaderView, tag: Tag) -> int: + row = header.sortIndicatorSection() + order = header.sortIndicatorOrder() + is_rev = is_reversed(row, order) + return todo.util.array.insert_position( + sort_key(tag, row, is_rev), + [sort_key(t, row, is_rev) for t in self._tags], + is_rev) + + def update_tag(self, header: QtWidgets.QHeaderView, row, tag: Tag) -> int: + self.delete_tag_range(row, 1) + return self.insert_tag(header, tag) + + def delete_tags(self, indexes): + for range in reversed(todo.util.range.from_indexes(indexes)): + self.delete_tag_range(range.start, range.length) + return True + + def delete_tag_range(self, row, rows): + self.beginRemoveRows(QtCore.QModelIndex(), row, row + rows - 1) + self._tags = self._tags[:row] + self._tags[row + rows:] + self.endRemoveRows() + return True + + def row_ids(self, rows): + return [tag.id for i, tag in enumerate(self._tags) if i in rows] + + def sort(self, row: int, order: Qt.SortOrder): + self.layoutAboutToBeChanged.emit() + is_rev = is_reversed(row, order) + self._tags = sorted( + self._tags, + key = lambda tag: sort_key(tag, row, is_rev), + reverse = is_rev) + self.layoutChanged.emit() + +def sort_key(tag: Tag, row: int, is_reversed: bool): + if row == 0: + return tag.name.lower() + elif row == 1: + return tag.color + +def is_reversed(row: int, order: Qt.SortOrder) -> bool: + return order == Qt.DescendingOrder diff --git a/todo/gui/tags/panel/table/widget.py b/todo/gui/tags/panel/table/widget.py new file mode 100644 index 0000000..b36759d --- /dev/null +++ b/todo/gui/tags/panel/table/widget.py @@ -0,0 +1,73 @@ +from PyQt5 import QtWidgets +from PyQt5.QtCore import Qt + +from todo.model.tag import Tag, ValidTagForm +import todo.database +import todo.db.tags +import todo.db.task_tags +import todo.gui.tags.panel.dialog +import todo.gui.tags.panel.signal +import todo.gui.tags.panel.table.menu +import todo.gui.tags.panel.table.model + +class Widget(QtWidgets.QTableView): + + def __init__(self, parent, add_tag_signal): + super().__init__(parent) + + self._update_tag_signal = todo.gui.tags.panel.signal.UpdateTag() + + tags = todo.db.tags.get(todo.database.cursor()) + table_model = todo.gui.tags.panel.table.model.TableModel(tags) + + self.setModel(table_model) + self.sortByColumn( + todo.gui.tags.panel.table.model.default_sort[0], + todo.gui.tags.panel.table.model.default_sort[1]) + self.setSortingEnabled(True) + self.setSelectionBehavior(QtWidgets.QTableView.SelectRows) + self.horizontalHeader().setStretchLastSection(True) + self.resizeColumns() + + self.doubleClicked.connect(lambda index: self.on_double_click(index.row())) + + # # Menu + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.customContextMenuRequested.connect(lambda position: todo.gui.tags.panel.table.menu.open(self, self._update_tag_signal, position)) + + add_tag_signal.connect(lambda tag: self.insert(tag)) + self._update_tag_signal.connect(lambda row, tag: self.update(row, tag)) + + def insert(self, tag): + self.model().insert_tag(self.horizontalHeader(), tag) + self.resizeColumns() + + def update(self, row, tag): + row = self.model().update_tag(self.horizontalHeader(), row, tag) + self.selectRow(row) + self.resizeColumns() + + def resizeColumns(self): + for column in range(todo.gui.tags.panel.table.model.columns): + self.resizeColumnToContents(column) + + def keyPressEvent(self, event): + super().keyPressEvent(event) + if event.key() in (Qt.Key_Return, Qt.Key_Enter): + rows = self.get_selected_rows() + if len(rows) == 1: + row = rows[0] + tag = self.model().get_at(row) + todo.gui.tags.panel.dialog.update(self, self._update_tag_signal, row, tag).exec_() + elif event.key() == Qt.Key_Delete: + rows = self.get_selected_rows() + tags = self.model().row_ids(rows) + if not db.task_tags.one_is_used(todo.database.cursor(), tags): + todo.gui.tags.panel.dialog.show_delete(self, rows) + + def get_selected_rows(self): + return list(set([index.row() for index in self.selectedIndexes()])) + + def on_double_click(self, row: int): + tag = self.model().get_at(row) + todo.gui.tags.panel.dialog.update(self, self._update_tag_signal, row, tag).exec_() |