Completed
Push — qml ( c742d9...e78c5d )
by Olivier
01:16
created

FiltersController.setFilters()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
c 2
b 0
f 0
dl 0
loc 2
rs 10
1
from PyQt5 import QtCore
2
from PyQt5 import QtGui
3
from qtodotxt.lib.filters import ContextFilter, CompleteTasksFilter, DueFilter, DueOverdueFilter, DueThisMonthFilter, \
4
    DueThisWeekFilter, DueTodayFilter, DueTomorrowFilter, HasContextsFilter, HasDueDateFilter, HasProjectsFilter, \
5
    ProjectFilter, UncategorizedTasksFilter, AllTasksFilter, PriorityFilter, HasPriorityFilter
6
from qtodotxt.lib.filters import SimpleTextFilter, FutureFilter, IncompleteTasksFilter
7
8
TotalCountRole = QtCore.Qt.UserRole + 1
9
CompletedCountRole = QtCore.Qt.UserRole + 2
10
11
12
class FilterItem(QtGui.QStandardItem):
13
    def __init__(self, parent, strings, flt=None, icon=None, order=None):
14
        QtGui.QStandardItem.__init__(self, strings)
15
        self.setSelectable(True)
16
        self.setEnabled(True)
17
        self.setData(flt, QtCore.Qt.UserRole)
18
        self.filter = flt
19
        parent.appendRow([self])
20
        #if order:
21
        #self.setText(1, str(order))
22
        self.iconSource = icon
23
24
    def setCounts(self, total, completed):
25
        self.setTotalCount(total)
26
        self.setCompletedCount(completed)
27
28
    def setTotalCount(self, total):
29
        self.setData(total, TotalCountRole)
30
31
    def setCompletedCount(self, val):
32
        self.setData(val, CompletedCountRole)
33
34
35
class FiltersModel(QtGui.QStandardItemModel):
36
    def __init__(self, parent):
37
        QtGui.QStandardItemModel.__init__(self, parent)
38
        self.style = ":/white_icons"
39
        if str(QtCore.QSettings().value("color_schem", "")).find("dark") >= 0:
40
            self.style = ":/dark_icons"
41
        self._filterItemByFilterType = dict()
42
        self._filterIconByFilterType = dict()
43
        self._treeItemByFilterType = dict()
44
        self._addDefaultTreeItems()
45
        self._initFilterTypeMappings()
46
47
    def roleNames(self):
48
        roles = QtGui.QStandardItemModel.roleNames(self)
49
        roles[TotalCountRole] = b"totalCount"
50
        roles[CompletedCountRole] = b"completedCount"
51
        return roles
52
53
    def addFilter(self, flt, counts):
54
        parent = self._filterItemByFilterType[type(flt)]
55
        item = FilterItem(parent, flt.text, flt)
56
        item.setCounts(*counts)
57
58
    def clear(self):
59
        QtGui.QStandardItemModel.clear(self)
60
        self._addDefaultTreeItems()
61
        self._initFilterTypeMappings()
62
63
    def _addDefaultTreeItems(self):
64
        self._allTasksItem = FilterItem(self, 'All', AllTasksFilter(), 'qtodotxt-filter-all')
65
        self._uncategorizedTasksItem = FilterItem(self, 'Uncategorized',
66
                                                  UncategorizedTasksFilter(), 'qtodotxt-filter-uncategorized')
67
        self._dueItem = FilterItem(self, 'Due', HasDueDateFilter(), 'qtodotxt-filter-due')
68
        self._contextsItem = FilterItem(self, 'Contexts', HasContextsFilter(), 'qtodotxt-filter-contexts')
69
        self._projectsItem = FilterItem(self, 'Projects', HasProjectsFilter(), 'qtodotxt-filter-projects')
70
        self._priorityItem = FilterItem(self, 'Priorities', HasPriorityFilter(), 'qtodotxt-filter-complete')
71
        self._completeTasksItem = FilterItem(self, 'Complete', CompleteTasksFilter(), 'qtodotxt-filter-complete')
72
73
    def _initFilterTypeMappings(self):
74
        self._filterItemByFilterType[ContextFilter] = self._contextsItem
75
        self._filterItemByFilterType[ProjectFilter] = self._projectsItem
76
        self._filterItemByFilterType[DueFilter] = self._dueItem
77
        self._filterItemByFilterType[PriorityFilter] = self._priorityItem
78
79
        self._filterIconByFilterType[ContextFilter] = 'qtodotxt-filter-contexts'
80
        self._filterIconByFilterType[ProjectFilter] = 'qtodotxt-filter-projects'
81
82
        self._filterIconByFilterType[DueTodayFilter] = 'qtodotxt-filter-due-today'
83
        self._filterIconByFilterType[DueTomorrowFilter] = 'qtodotxt-filter-due-tomorrow'
84
        self._filterIconByFilterType[DueThisWeekFilter] = 'qtodotxt-filter-due-week'
85
        self._filterIconByFilterType[DueThisMonthFilter] = 'qtodotxt-filter-due-month'
86
        self._filterIconByFilterType[DueOverdueFilter] = 'qtodotxt-filter-due-overdue'
87
        self._filterIconByFilterType[PriorityFilter] = 'qtodotxt-filter-complete'
88
89
        self._treeItemByFilterType[AllTasksFilter] = self._allTasksItem
90
        self._treeItemByFilterType[UncategorizedTasksFilter] = self._uncategorizedTasksItem
91
        self._treeItemByFilterType[CompleteTasksFilter] = self._completeTasksItem
92
        self._treeItemByFilterType[HasProjectsFilter] = self._projectsItem
93
        self._treeItemByFilterType[HasDueDateFilter] = self._dueItem
94
        self._treeItemByFilterType[HasContextsFilter] = self._contextsItem
95
        self._treeItemByFilterType[HasPriorityFilter] = self._priorityItem
96
97
    # Predefined sorting for due ranges
98
    def addDueRangeFilter(self, flt, counts, sortKey=0):
99
        parentItem = self._dueItem
100
        icon = self._filterIconByFilterType[type(flt)]
101
        item = FilterItem(parentItem, flt.text, flt=flt, icon=icon, order=sortKey)
102
        item.setCounts(*counts)
103
104
        #parentItem.setExpanded(True)
105
        #parentItem.sortChildren(1, QtCore.Qt.AscendingOrder)
106
107
    @QtCore.pyqtSlot(result='QVariantList')
108
    def getRootChildren(self):
109
        indexes = []
110
        parent = self.invisibleRootItem()
111
        for i in range(0, parent.rowCount()):
112
            child = parent.child(i)
113
            indexes.append(child.index())
114
        return indexes
115
116
    @QtCore.pyqtSlot('QModelIndex', result='QString')
117
    def iconFromIndex(self, index):
118
        source = ""
119
        item = super(FiltersModel, self).itemFromIndex(index)
120
        if item is not None:
121
            source = item.iconSource
122
        return source
123
124
    @QtCore.pyqtSlot('int', result='QString')
125
    def iconFromRow(self, row):
126
        print(row)
127
        path = ""
128
        if row > 0 and row < self.rowCount():
129
            path = self.item(row, 0).iconSource
130
        return path
131
132
    def updateCounters(self, counters):
133
        self._completeTasksItem.setTotalCount(counters['All'][1])
134
        self._allTasksItem.setCounts(*counters['All'])
135
        self._dueItem.setCounts(*counters['Due'])
136
        self._contextsItem.setCounts(*counters['Contexts'])
137
        self._projectsItem.setCounts(*counters['Projects'])
138
        self._priorityItem.setCounts(*counters['Priority'])
139
        self._uncategorizedTasksItem.setCounts(*counters['Uncategorized'])
140
141
142
class FiltersController(QtCore.QObject):
143
144
    filterSelectionChanged = QtCore.pyqtSignal(list)
145
146
    def __init__(self):
147
        QtCore.QObject.__init__(self)
148
        self._settings = QtCore.QSettings()
149
        self.model = FiltersModel(self)
150
        self.showCompleted = self._settings.value("show_completed", False)
151
        self.showFuture = self._settings.value("show_completed", True)
152
        self.searchText = ""
153
        # self.currentFilters = self._settings.value("current_filters", ["All"])  # move to QML
154
        self.currentFilters = []
155
156
    def setFiltersByIndexes(self, idxs):
157
        filters = [self.model.itemFromIndex(idx).filter for idx in idxs]
158
        self.setFilters(filters)
159
160
    def setFilters(self, filters):
161
        self.currentFilters = filters
162
163
    def filter(self, tasks):
164
        # First we filter with filters tree
165
        tasks = filterTasks(self.currentFilters, tasks)
166
        # Then with our search text
167
        if self.searchText:
168
            tasks = filterTasks([SimpleTextFilter(self.searchText)], tasks)
169
        # with future filter if needed
170
        if not self.showFuture:
171
            tasks = filterTasks([FutureFilter()], tasks)
172
        # with complete filter if needed
173
        if not self.showCompleted and CompleteTasksFilter() not in self.currentFilters:
174
            tasks = filterTasks([IncompleteTasksFilter()], tasks)
175
        return tasks
176
177
    def updateFiltersModel(self, mfile):
178
        self.model.clear()
179
        self._addAllContexts(mfile)
180
        self._addAllProjects(mfile)
181
        self._addAllDueRanges(mfile)
182
        self._addAllPriorities(mfile)
183
        self._updateCounter(mfile)
184
185
    def _updateCounter(self, mfile):
186
        counters = mfile.getTasksCounters()
187
        self.model.updateCounters(counters)
188
189
    def _addAllContexts(self, mfile):
190
        contexts = mfile.getAllContexts()
191
        for context, number in contexts.items():
192
            mfilter = ContextFilter(context)
193
            self.model.addFilter(mfilter, number)
194
195
    def _addAllProjects(self, mfile):
196
        projects = mfile.getAllProjects()
197
        for project, counts in projects.items():
198
            mfilter = ProjectFilter(project)
199
            self.model.addFilter(mfilter, counts)
200
201
    def _addAllPriorities(self, mfile):
202
        priorities = mfile.getAllPriorities()
203
        for priority, number in priorities.items():
204
            mfilter = PriorityFilter(priority)
205
            self.model.addFilter(mfilter, number)
206
207
    def _addAllDueRanges(self, mfile):
208
        dueRanges = mfile.getAllDueRanges()
209
210
        for flt, counts in dueRanges.items():
211
            self.model.addDueRangeFilter(flt, counts)
212
213
214
def filterTasks(filters, tasks):
215
    if not filters:
216
        return tasks[:]
217
218
    filteredTasks = []
219
    for task in tasks:
220
        for myfilter in filters:
221
            if myfilter.isMatch(task):
222
                filteredTasks.append(task)
223
                break
224
    return filteredTasks
225
226
227