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