1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import collections
20 import contextlib
21
22 from timelinelib.calendar.gregorian.timetype import GregorianTimeType
23 from timelinelib.canvas.data.exceptions import TimelineIOError
24 from timelinelib.canvas.data.immutable import ImmutableDB
25 from timelinelib.canvas.data import Category
26 from timelinelib.canvas.data import Container
27 from timelinelib.canvas.data import Era
28 from timelinelib.canvas.data import Eras
29 from timelinelib.canvas.data import Event
30 from timelinelib.canvas.data import Milestone
31 from timelinelib.canvas.data import Subevent
32 from timelinelib.canvas.data import TimePeriod
33 from timelinelib.canvas.data.transactions import Transactions
34 from timelinelib.general.observer import Observable
35
36
37
38 STATE_CHANGE_CATEGORY = 1
39
40 STATE_CHANGE_ANY = 2
44
46 Observable.__init__(self)
47 self._id_counter = 0
48 self._transactions = Transactions(ImmutableDB())
49 self._transactions.listen_for_any(self._transaction_committed)
50 self.path = ""
51 self.displayed_period = None
52 self._hidden_category_ids = []
53 self.time_type = GregorianTimeType()
54 self.saved_now = self.time_type.now()
55 self.readonly = False
56 self._save_callback = None
57 self._should_lock = False
58 self._current_query = None
59
61 return self._create_wrapper(Category, **kwargs)
62
64 return self._create_wrapper(Milestone, **kwargs)
65
67 return self._create_wrapper(Era, **kwargs)
68
70 return self._create_wrapper(Event, **kwargs)
71
73 return self._create_wrapper(Container, **kwargs)
74
76 return self._create_wrapper(Subevent, **kwargs)
77
92
94 self._id_counter += 1
95 return self._id_counter
96
98 return self._transactions.new(name)
99
101 self._transactions.clear()
102
104 return self._transactions.status
105
108
110 return self._save_callback is not None
111
113 return self._should_lock
114
116 self._should_lock = should_lock
117
119 self._save_callback = callback
120
122 return self.time_type
123
125 self.time_type = time_type
126 if time_type is not None:
127 self.saved_now = time_type.now()
128
131
135
136 - def search(self, search_string):
137 return _generic_event_search(self.get_all_events(), search_string)
138
143
145 return self._get_events(lambda immutable_event: True)
146
158
160 with self._query() as query:
161 return (
162 self._get_milestones(criteria_fn) +
163 sort_events(self.get_containers() + [
164 query.get_event(id_)
165 for id_, immutable_event
166 in self._transactions.value.events
167 if criteria_fn(immutable_event)
168 ])
169 )
170
172 with self._query() as query:
173 return [
174 query.get_milestone(id_)
175 for id_, immutable_milestone
176 in self._transactions.value.milestones
177 if criteria_fn(immutable_milestone)
178 ]
179
181 if len(self._transactions.value.events) == 0:
182 return None
183 else:
184 id_, immutable_event = min(
185 self._transactions.value.events,
186 key=lambda id__immutable_event:
187 id__immutable_event[1].time_period.start_time
188 )
189 with self._query() as query:
190 return query.get_event(id_)
191
193 if len(self._transactions.value.events) == 0:
194 return None
195 else:
196 id_, immutable_event = max(
197 self._transactions.value.events,
198 key=lambda id__immutable_event1:
199 id__immutable_event1[1].time_period.end_time
200 )
201 with self._query() as query:
202 return query.get_event(id_)
203
212
215
226
228 return self._get_eras().get_all()
229
232
234 with self._query() as query:
235 return Eras(
236 now_func=self.time_type.now,
237 eras=[
238 query.get_era(id_)
239 for id_, immutable_era
240 in self._transactions.value.eras
241 ]
242 )
243
250
257
259 with self._query() as query:
260 return [
261 query.get_category(id_)
262 for id_, immutable_category
263 in self._transactions.value.categories
264 ]
265
267 with self._query() as query:
268 return [
269 query.get_container(id_)
270 for id_, immutable_container
271 in self._transactions.value.containers
272 ]
273
280
282 with self._query() as query:
283 for id_, immutable_category in self._transactions.value.categories:
284 if immutable_category.name == name:
285 return query.get_category(id_)
286 return None
287
292
306
308 return self.saved_now
309
313
315 view_properties.displayed_period = self.displayed_period
316 for cat in self.get_categories():
317 visible = cat.id not in self._hidden_category_ids
318 view_properties.set_category_visible(cat, visible)
319
321 if view_properties.displayed_period is not None:
322 if not view_properties.displayed_period.is_period():
323 raise TimelineIOError(_("Displayed period must be > 0."))
324 self.displayed_period = view_properties.displayed_period
325 self._hidden_category_ids = []
326 for cat in self.get_categories():
327 if not view_properties.is_category_visible(cat):
328 self._hidden_category_ids.append(cat.id)
329 self._save()
330
332 self._place_event(
333 lambda index_to_place, index_target: index_to_place < index_target,
334 event_to_place.id,
335 target_event.id
336 )
337
339 self._place_event(
340 lambda index_to_place, index_target: index_to_place > index_target,
341 event_to_place.id,
342 target_event.id
343 )
344
345 - def _place_event(self, validate_index, id_to_place, id_target):
357
363
364 - def _move(self, events, validate_index, id_to_place, id_target):
365 index_to_place = None
366 index_target = None
367 for index, event in enumerate(events):
368 if event.id == id_to_place:
369 index_to_place = index
370 if event.id == id_target:
371 index_target = index
372 if index_to_place is None:
373 return False
374 if index_target is None:
375 return False
376 if validate_index(index_to_place, index_target):
377 events.insert(index_target, events.pop(index_to_place))
378 return True
379 return False
380
382 index = self._get_undo_index()
383 if index is not None:
384 self._transactions.move(index)
385
387 index = self._get_redo_index()
388 if index is not None:
389 self._transactions.move(index)
390
392 return not self.is_read_only() and self._get_undo_index() is not None
393
395 return not self.is_read_only() and self._get_redo_index() is not None
396
398 index, is_in_transaction, history = self._transactions.status
399 if index > 0:
400 return index - 1
401 else:
402 return None
403
405 index, is_in_transaction, history = self._transactions.status
406 if index < len(history) - 1:
407 return index + 1
408 else:
409 return None
410
416
425
429
431 if self._save_callback is not None:
432 self._save_callback()
433
435 """
436 Inheritors can call this method to get the displayed period used in
437 load_view_properties and save_view_properties.
438 """
439 return self.displayed_period
440
442 """
443 Inheritors can call this method to set the displayed period used in
444 load_view_properties and save_view_properties.
445 """
446 self.displayed_period = period
447
449 with self._query() as query:
450 return [
451 query.get_category(id_)
452 for id_
453 in self._hidden_category_ids
454 ]
455
457 self._hidden_category_ids = []
458 for cat in hidden_categories:
459 if cat.id not in self._transactions.value.categories:
460 raise ValueError("Category '%s' not in db." % cat.get_name())
461 self._hidden_category_ids.append(cat.id)
462
469
483
494
500
502 with self.transaction("Compress events"):
503 self._set_events_order_from_rows(self._place_events_on_rows())
504
509
511 rows = collections.defaultdict(lambda: [])
512 for event in self._length_sort():
513 inx = 0
514 while True:
515 if self._fits_on_row(rows[inx], event):
516 event.r = inx
517 rows[inx].append(event)
518 break
519 inx += 1
520 return rows
521
532
534 return sorted(events, key=self._event_length, reverse=True)
535
538
540 for ev in row_events:
541 if ev.overlaps(event):
542 return False
543 return True
544
545 @contextlib.contextmanager
547 need_to_create_query = self._current_query is None
548 if need_to_create_query:
549 self._current_query = Query(self, self._transactions.value)
550 try:
551 yield self._current_query
552 finally:
553 if need_to_create_query:
554 self._current_query = None
555
558
560 self._db = db
561 self._immutable_db = immutable_db
562 self._wrappers = {}
563
566
568 return id_ in self._immutable_db.events
569
572
574 if id_ not in self._wrappers:
575 self._wrappers[id_] = self._create_category_wrapper(id_)
576 return self._wrappers[id_]
577
579 if id_ not in self._wrappers:
580 self._wrappers[id_] = self._create_container_wrapper(id_)
581 self._load_subevents(self._wrappers[id_])
582 return self._wrappers[id_]
583
585 if id_ not in self._wrappers:
586 self._wrappers[id_] = self._create_event_wrapper(id_)
587 immutable_event = self._immutable_db.events.get(id_)
588 if immutable_event.container_id is not None:
589
590 self.get_container(immutable_event.container_id)
591 return self._wrappers[id_]
592
594 if id_ not in self._wrappers:
595 self._wrappers[id_] = self._create_milestone_wrapper(id_)
596 return self._wrappers[id_]
597
599 if id_ not in self._wrappers:
600 self._wrappers[id_] = self._create_era_wrapper(id_)
601 return self._wrappers[id_]
602
607
609 immutable_category = self._immutable_db.categories.get(id_)
610 wrapper = Category(
611 db=self._db,
612 id_=id_,
613 immutable_value=immutable_category,
614 )
615 wrapper.parent = self._get_maybe_category(immutable_category.parent_id)
616 return wrapper
617
619 immutable_container = self._immutable_db.containers.get(id_)
620 wrapper = Container(
621 db=self._db,
622 id_=id_,
623 immutable_value=immutable_container,
624 )
625 wrapper.category = self._get_maybe_category(immutable_container.category_id)
626 return wrapper
627
629 immutable_event = self._immutable_db.events.get(id_)
630 if immutable_event.container_id is None:
631 klass = Event
632 else:
633 klass = Subevent
634 wrapper = klass(
635 db=self._db,
636 id_=id_,
637 immutable_value=immutable_event,
638 )
639 wrapper.category = self._get_maybe_category(immutable_event.category_id)
640 return wrapper
641
643 immutable_milestone = self._immutable_db.milestones.get(id_)
644 wrapper = Milestone(
645 db=self._db,
646 id_=id_,
647 immutable_value=immutable_milestone,
648 )
649 wrapper.category = self._get_maybe_category(immutable_milestone.category_id)
650 return wrapper
651
653 immutable_era = self._immutable_db.eras.get(id_)
654 return Era(
655 db=self._db,
656 id_=id_,
657 immutable_value=immutable_era,
658 )
659
665
681
685
696 def mean_time(event):
697 return event.mean_time()
698 matches = [event for event in events if match(event)]
699 matches.sort(key=mean_time)
700 return matches
701