aboutsummaryrefslogtreecommitdiff
path: root/src/gui/tasks/table/model.py
blob: ab969ecf930a83fc476a720baf49a7a46134a991 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtCore import Qt

from model.task import Task
from model.difficulty import Difficulty
from model.priority import Priority
from model import difficulty, priority
import time
import math
import util.array
import util.range
import gui.tasks.duration
import gui.color

columns = 6

headers = ['Age', 'Name', 'Duration', 'Difficulty', 'Priority', 'Tag']

default_sort = (0, Qt.AscendingOrder)

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, tasks):
        super(TableModel, self).__init__()
        self._tasks = tasks

    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):
        task = self._tasks[index.row()]

        if role == Qt.DisplayRole:
            if index.column() == 0:
                return age_since(task.created_at)
            elif index.column() == 1:
                return task.name
            elif index.column() == 2:
                return gui.tasks.duration.format(task.duration)
            elif index.column() == 3:
                return difficulty.format(task.difficulty)
            elif index.column() == 4:
                return priority.format(task.priority)
            elif index.column() == 5:
                return task.tag
        elif role == Qt.ForegroundRole:
            if index.column() == 2:
                return QtGui.QBrush(gui.tasks.duration.color(task.duration))
            elif index.column() == 3:
                return QtGui.QBrush(difficulty_color(task.difficulty))
            elif index.column() == 4:
                return QtGui.QBrush(priority_color(task.priority))
        else:
            return QtCore.QVariant()

    def rowCount(self, index):
        return len(self._tasks)

    def columnCount(self, index):
        return columns

    def get_at(self, row):
        if row >= 0 and row < len(self._tasks):
            return self._tasks[row]


    def insert_task(self, header: QtWidgets.QHeaderView, task: Task) -> int:
        at = self.insert_position(header, task)
        self.beginInsertRows(QtCore.QModelIndex(), at, at)
        self._tasks.insert(at, task)
        self.endInsertRows()
        return at

    def insert_position(self, header: QtWidgets.QHeaderView, task: Task) -> int:
        row = header.sortIndicatorSection()
        order = header.sortIndicatorOrder()
        is_rev = is_reversed(row, order)
        return util.array.insert_position(
                sort_key(task, row, is_rev),
                [sort_key(t, row, is_rev) for t in self._tasks],
                is_rev)

    def update_task(self, header: QtWidgets.QHeaderView, row, task: Task) -> int:
        self.delete_task_range(row, 1)
        return self.insert_task(header, task)

    def delete_tasks(self, indexes):
        for range in reversed(util.range.from_indexes(indexes)):
            self.delete_task_range(range.start, range.length)
        return True

    def delete_task_range(self, row, rows):
        self.beginRemoveRows(QtCore.QModelIndex(), row, row + rows - 1)
        self._tasks = self._tasks[:row] + self._tasks[row + rows:]
        self.endRemoveRows()
        return True

    def row_ids(self, rows):
        return [task.id for i, task in enumerate(self._tasks) if i in rows]

    def sort(self, row: int, order: Qt.SortOrder):
        self.layoutAboutToBeChanged.emit()
        is_rev = is_reversed(row, order)
        self._tasks = sorted(
                self._tasks,
                key = lambda task: sort_key(task, row, is_rev),
                reverse = is_rev)
        self.layoutChanged.emit()

def age_since(timestamp):
    diff = int(time.time()) - timestamp
    if diff >= 60 * 60 * 24:
        return '' + str(math.floor(diff / 60 / 60 / 24)) + 'd'
    elif diff >= 60 * 60:
        return '' + str(math.floor(diff / 60 / 60)) + 'h'
    elif diff >= 60:
        return '' + str(math.floor(diff / 60)) + 'm'
    else:
        return '1m'

def sort_key(task: Task, row: int, is_reversed: bool):
    if row == 0:
        return task.created_at
    elif row == 1:
        return task.name.lower()
    elif row == 2:
        if is_reversed:
            return task.duration
        else:
            return (task.duration == 0, task.duration)
    elif row == 3:
        return task.difficulty
    elif row == 4:
        return task.priority
    elif row == 5:
        if is_reversed:
            return task.tag.lower()
        else:
            return (task.tag == '', task.tag.lower())

def is_reversed(row: int, order: Qt.SortOrder) -> bool:
    if row == 0:
        return order == Qt.AscendingOrder
    else:
        return order == Qt.DescendingOrder

def difficulty_color(d: Difficulty) -> QtGui.QColor:
    if d == Difficulty.EASY:
        return gui.color.easy_difficulty
    elif d == Difficulty.NORMAL:
        return gui.color.normal_difficulty
    elif d == Difficulty.HARD:
        return gui.color.hard_difficulty

def priority_color(p: Priority) -> QtGui.QColor:
    if p == Priority.LOW:
        return gui.color.low_priority
    elif p == Priority.MIDDLE:
        return gui.color.middle_priority
    elif p == Priority.HIGH:
        return gui.color.high_priority