1
|
|
|
from datetime import datetime |
2
|
|
|
from PyQt5 import QtCore |
3
|
|
|
|
4
|
|
|
|
5
|
|
|
class TaskHtmlizer(object): |
6
|
|
|
def __init__(self): |
7
|
|
|
colorSchemName = QtCore.QSettings().value("color_schem", "") |
8
|
|
|
if str(colorSchemName).find("dark") >= 0: # for dark theme |
9
|
|
|
self.priority_colors = dict(A='red', B='#1C7F61', C='#7397BE') |
10
|
|
|
self.contextColor = "#5ED2B8" |
11
|
|
|
self.projectColor = "#FFCA73" |
12
|
|
|
self.priorityDuecolors = ['red', '#E0A180'] |
13
|
|
|
self.priorityThresholdColors = ['orange', 'grey'] |
14
|
|
|
self.errorColor = "red" |
15
|
|
|
self.linkColor = "#E0A180" |
16
|
|
|
else: # for light theme |
17
|
|
|
self.priority_colors = dict(A='red', B='green', C='navy') |
18
|
|
|
self.contextColor = "green" |
19
|
|
|
self.projectColor = "#64AAD0" |
20
|
|
|
self.priorityDuecolors = ['red', 'orange'] |
21
|
|
|
self.priorityThresholdColors = ['orange', 'grey'] |
22
|
|
|
self.errorColor = "red" |
23
|
|
|
self.linkColor = "none" |
24
|
|
|
|
25
|
|
|
self.complColor = "gray" |
26
|
|
|
|
27
|
|
|
def task2html(self, task): |
28
|
|
|
words = task.description.split(" ") |
29
|
|
|
newwords = [] |
30
|
|
|
for word in words: |
31
|
|
|
if word.startswith("@"): |
32
|
|
|
word = self._htmlizeContext(word) |
33
|
|
|
elif word.startswith("+"): |
34
|
|
|
word = self._htmlizeProject(word) |
35
|
|
|
elif word.startswith("due:"): |
36
|
|
|
word = self._htmlizeDueDate(task, word) |
37
|
|
|
elif word.startswith("t:"): |
38
|
|
|
word = self._htmlizeThresholdDate(task, word) |
39
|
|
|
elif "://" in word: |
40
|
|
|
word = self._addUrl(word, self.linkColor) |
41
|
|
|
newwords.append(word) |
42
|
|
|
html = " ".join(newwords) |
43
|
|
|
if task.is_complete: |
44
|
|
|
html = '<s>{}</s>'.format(html) |
45
|
|
|
if task.priority: |
46
|
|
|
html = self._htmlizePriority(task.priority) + html |
47
|
|
|
else: |
48
|
|
|
# add space, so tasks get evenly aligned when there's no priority |
49
|
|
|
html = '<tt> </tt> ' + html |
50
|
|
|
if task.completion_date: |
51
|
|
|
html += ' <font color="{1!s}">(completed: {0!s})</font>'.format(task.completion_date, self.complColor) |
52
|
|
|
if task.creation_date: |
53
|
|
|
html += ' <font color="{1!s}">(created: {0!s})</font>'.format(task.creation_date, self.complColor) |
54
|
|
|
return html |
55
|
|
|
|
56
|
|
|
def _addUrl(self, word, color="none"): |
57
|
|
|
if ("http" in word) or ("www." in word): |
58
|
|
|
parts = word.split('//', 1) |
59
|
|
|
parts2 = parts[1].split('/') |
60
|
|
|
end = parts2[0] |
61
|
|
|
if len(parts2) > 1: |
62
|
|
|
end += "/..." |
63
|
|
|
cleanWord = parts[0] + '//' + end |
64
|
|
|
else: |
65
|
|
|
parts = word.split('/') |
66
|
|
|
if len(parts[-1]): |
67
|
|
|
cleanWord = parts[-1] |
68
|
|
|
else: |
69
|
|
|
cleanWord = parts[-2] |
70
|
|
|
cleanWord = "../" + cleanWord |
71
|
|
|
word = '<a style="color:{2!s};" href="{0!s}">{1!s}</a>'.format(word, cleanWord, color) |
72
|
|
|
return word |
73
|
|
|
|
74
|
|
|
def _htmlizeContext(self, context): |
75
|
|
|
context = context.replace("@", "") |
76
|
|
|
if "://" in context: |
77
|
|
|
context = self._addUrl(context, self.contextColor) |
78
|
|
|
|
79
|
|
|
return '<font style="color:{0!s}">@{1!s}</font>'.format(self.contextColor, context) |
80
|
|
|
|
81
|
|
|
def _htmlizeProject(self, project): |
82
|
|
|
project = project.replace("+", "") |
83
|
|
|
if "://" in project: |
84
|
|
|
project = self._addUrl(project, self.projectColor) |
85
|
|
|
|
86
|
|
|
return '<font style="color:{0!s}">+{1!s}</font>'.format(self.projectColor, project) |
87
|
|
|
|
88
|
|
|
def _htmlizePriority(self, priority): |
89
|
|
|
if priority in self.priority_colors: |
90
|
|
|
color = self.priority_colors[priority] |
91
|
|
|
return '<font style="color:{}"><tt>({})</tt> </font>'.format(color, priority) |
92
|
|
|
return '<tt>(%s)</tt> ' % priority |
93
|
|
|
|
94
|
|
|
def _htmlizeDueDate(self, task, string): |
95
|
|
|
if not task.due: |
96
|
|
|
return ('<b><font style="color:{1!s}">*** {0!s} Invalid date format,' |
97
|
|
|
' expected yyyy-mm-dd or yyyy-mm-ddThh:mm. ***</font></b>'.format(string, self.errorColor)) |
98
|
|
|
|
99
|
|
|
date_now = datetime.today() |
100
|
|
|
tdelta = task.due - date_now |
101
|
|
|
if tdelta.days > 7: |
102
|
|
|
return '<b>due:{}</b>'.format(task.dueString) |
103
|
|
|
elif tdelta.days > 0: |
104
|
|
|
return '<b><font style="color:{1!s}">due:{0!s}</font></b>'.format(task.dueString, self.priorityDuecolors[1]) |
105
|
|
|
else: |
106
|
|
|
return '<b><font style="color:{1!s}">due:{0!s}</font></b>'.format(task.dueString, self.priorityDuecolors[0]) |
107
|
|
|
|
108
|
|
|
def _htmlizeThresholdDate(self, task, string): |
109
|
|
|
if not task.threshold: |
110
|
|
|
return ('<b><font style="color:{1!s}">*** {0!s} Invalid date format,' |
111
|
|
|
' expected yyyy-mm-dd or yyyy-mm-ddThh:mm. ***</font></b>'.format(string, self.errorColor)) |
112
|
|
|
|
113
|
|
|
date_now = datetime.today() |
114
|
|
|
tdelta = task.threshold - date_now |
115
|
|
|
if tdelta.days > 0: |
116
|
|
|
return '<i><font style="color:{1!s}">t:{0!s}</font></i>'.\ |
117
|
|
|
format(task.thresholdString, self.priorityThresholdColors[1]) |
118
|
|
|
else: |
119
|
|
|
return '<font style="color:{1!s}">t:{0!s}</font>'.\ |
120
|
|
|
format(task.thresholdString, self.priorityThresholdColors[0]) |
121
|
|
|
|