|
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
|
|
|
|