1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 from datetime import date
20 from datetime import datetime
21 from datetime import timedelta
22 from os.path import abspath
23 import random
24
25 from icalendar import Calendar
26
27 from timelinelib.calendar.gregorian.gregorian import GregorianDateTime
28 from timelinelib.calendar.gregorian.time import GregorianDelta
29 from timelinelib.canvas.data.db import MemoryDB
30 from timelinelib.canvas.data.exceptions import TimelineIOError
31 from timelinelib.canvas.data import Category
32 from timelinelib.canvas.data import Event
33 from timelinelib.utils import ex_msg
34 from timelinelib.wxgui.utils import display_warning_message
35
36
38
39 - def load(self, db, path, options):
40 self.vevents_not_loaded = []
41 (self.add_location_to_description,
42 self.use_trigger_as_start_date,
43 self.use_trigger_as_alert) = options
44 self.events = []
45 self.categories = []
46 self.category_names = []
47 file_contents = self._read_file_content(path)
48 cal = self._read_calendar_object(file_contents)
49 self._load_events(cal, db)
50 self._load_todos(cal, db)
51 self._save_data_in_db(db)
52 self._report_on_vevents_not_loaded()
53
55 for vevent in cal.walk("VEVENT"):
56 self._load_vevent(db, vevent)
57 self._load_categories(vevent)
58
60 for vtodo in cal.walk("VTODO"):
61 self._load_vtodo(db, vtodo)
62 self._load_categories(vtodo)
63
74
76 end = self._extract_todo_end(vtodo)
77 if self.use_trigger_as_start_date:
78 start = self._extract_todo_start(vtodo)
79 if start is None:
80 start = end
81 else:
82 start = end
83 return start, end
84
86 end = self._get_value(vtodo, "due")
87 if end:
88 return self._convert_to_datetime(end)
89 else:
90 raise KeyError("Start time not found")
91
93 valarm = self._get_first_subelement(vtodo, "VALARM")
94 if valarm:
95 start = self._get_value(valarm, "trigger")
96 if start:
97 return self._convert_to_datetime(start)
98
100 if self.add_location_to_description:
101 if "location" in vtodo:
102 return "%s: %s" % (_("Location"), vtodo["location"])
103 else:
104 return None
105 else:
106 return None
107
109 if self.use_trigger_as_alert:
110 start = self._extract_todo_start(vtodo)
111 if start is not None:
112 return (start, "")
113
115 try:
116 return Calendar.from_ical(file_contents)
117 except Exception as pe:
118 msg1 = _("Unable to read calendar data.")
119 msg2 = "\n\n" + ex_msg(pe)
120 raise TimelineIOError(msg1 + msg2)
121
122 - def _read_file_content(self, path):
123 ics_file = None
124 try:
125 ics_file = open(path, "rb")
126 return ics_file.read()
127 except IOError as e:
128 msg = _("Unable to read from file '%s'.")
129 whole_msg = (msg + "\n\n%s") % (abspath(path), e)
130 raise TimelineIOError(whole_msg)
131 finally:
132 if ics_file is not None:
133 ics_file.close()
134
140
150
152 if "categories" in vevent:
153 categories_names = [cat.strip() for cat in vevent["categories"].split(",") if len(cat.strip()) > 0]
154 for category_name in categories_names:
155 if category_name not in self.category_names:
156 self.categories.append(Category().update(
157 category_name,
158 self._get_random_color(),
159 None
160 ))
161 self.category_names.append(category_name)
162
164 return (random.randint(0, 255),
165 random.randint(0, 255),
166 random.randint(0, 255))
167
169 return self._get_first_value(vevent, ["summary", "description"], "")
170
172 if self.add_location_to_description:
173 if "location" in vevent:
174 sep = ""
175 if "description" in vevent:
176 sep = "\n\n"
177 return "%s%s%s: %s" % (self._get_value(vevent, "description", ""),
178 sep,
179 _("Location"),
180 self._get_value(vevent, "location", ""))
181 else:
182 return self._get_value(vevent, "description", None)
183 else:
184 return self._get_value(vevent, "description", None)
185
187 for key in key_list:
188 if key in element:
189 return element[key]
190 return not_found_value
191
192 - def _get_value(self, element, key, not_found_value=None):
193 if key in element:
194 return element.decoded(key)
195 return not_found_value
196
198 start = self._convert_to_datetime(vevent.decoded("dtstart"))
199 if "dtend" in vevent:
200 end = self._convert_to_datetime(vevent.decoded("dtend"))
201 elif "duration" in vevent:
202 end = start + self._convert_to_timedelta(vevent.decoded("duration"))
203 else:
204 end = self._convert_to_datetime(vevent.decoded("dtstart"))
205 return (start, end)
206
212
220
222 subelements = self._get_subelements(parent, subelement_name)
223 if len(subelements) > 0:
224 return subelements[0]
225
227 return parent.walk(subelement_name)
228
230 if len(self.vevents_not_loaded) > 0:
231 message = ("Some events couldn't be loaded!\n" +
232 "The first 10 failing events are shown below.\n" +
233 self._format_vevents_not_loaded())
234 display_warning_message(message)
235
240
241 - def _time_to_text(self, time):
245
246
264