1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 from timelinelib.canvas.data.timeperiod import TimePeriod
20
21
23 """
24 The list of all eras defined for a timeline.
25
26 Contains function for cloning of the whole list which is a
27 necessary operation for undo/redo operations.
28 """
29
30 - def __init__(self, now_func, eras=None):
31 self.now_func = now_func
32 if eras is None:
33 self._eras = []
34 else:
35 self._eras = eras
36
38 return sorted(self._eras)
39
44
45 def merge_colors(c1, c2):
46 return ((c1[0] + c2[0]) / 2, (c1[1] + c2[1]) / 2, (c1[2] + c2[2]) / 2)
47
48 def create_overlapping_era(e0, e1, start, end):
49 era = e1.duplicate()
50 era.set_time_period(TimePeriod(start, end))
51 era.set_color(merge_colors(e0.get_color(), e1.get_color()))
52 era.set_name("%s + %s" % (e0.get_name(), e1.get_name()))
53 return era
54
55 def get_start_and_end_times(e0, e1):
56 e0start = e0.get_time_period().start_time
57 e0end = e0.get_time_period().end_time
58 e1start = e1.get_time_period().start_time
59 e1end = e1.get_time_period().end_time
60 return e0start, e0end, e1start, e1end
61
62 def return_era_for_overlapping_type_1(e0, e1):
63 e0start, e0end, e1start, e1end = get_start_and_end_times(e0, e1)
64 era = create_overlapping_era(e0, e1, e1start, e0end)
65 e0.set_time_period(TimePeriod(e0start, e1start))
66 e1.set_time_period(TimePeriod(e0end, e1end))
67 return era
68
69 def return_era_for_overlapping_type_2(e0, e1):
70 e0start, e0end, _, e1end = get_start_and_end_times(e0, e1)
71 era = create_overlapping_era(e0, e1, e0start, e0end)
72 self.all_eras.remove(e0)
73 e1.set_time_period(TimePeriod(e0end, e1end))
74 return era
75
76 def return_era_for_overlapping_type_3(e0, e1):
77 return return_era_for_overlapping_type_2(e1, e0)
78
79 def return_era_for_overlapping_type_4(e0, e1):
80 _, _, e1start, e1end = get_start_and_end_times(e0, e1)
81 era = create_overlapping_era(e0, e1, e1start, e1end)
82 self.all_eras.remove(e0)
83 self.all_eras.remove(e1)
84 return era
85
86 def return_era_for_overlapping_type_5(e0, e1):
87 e0start, _, e1start, e1end = get_start_and_end_times(e0, e1)
88 era = create_overlapping_era(e0, e1, e1start, e1end)
89 e0.set_time_period(TimePeriod(e0start, e1start))
90 self.all_eras.remove(e1)
91 return era
92
93 def return_era_for_overlapping_type_6(e0, e1):
94 e0start, e0end, e1start, e1end = get_start_and_end_times(e0, e1)
95 era = create_overlapping_era(e0, e1, e1start, e1end)
96 e0.set_time_period(TimePeriod(e0start, e1start))
97 e1.set_time_period(TimePeriod(e1end, e0end))
98 e1.set_name(e0.get_name())
99 e1.set_color(e0.get_color())
100 return era
101
102 def clone_all_eras():
103 return [e.duplicate() for e in self.get_all()]
104
105 overlap_func = (None,
106 return_era_for_overlapping_type_1,
107 return_era_for_overlapping_type_2,
108 return_era_for_overlapping_type_3,
109 return_era_for_overlapping_type_4,
110 return_era_for_overlapping_type_5,
111 return_era_for_overlapping_type_6)
112
113 def create_overlapping_era_and_remove_hidden_eras():
114 """
115 self.all_eras is always sorted by Era start time.
116 This method finds the first pair of Era's that overlaps.
117 If such a pair is found, a overlapping Era is created and added
118 to the the self.all_eras list. If any or both of the original
119 Era's are hidden by the overlapping Era, they are removed from
120 the self.all_eras list.
121 When one overlapping pair has been found and processed the
122 function returns False, after updating the self.all_eras list
123 If no overlapping pairs of Era's are found the function retuns
124 True.
125 """
126 e0 = self.all_eras[0]
127 for e1 in self.all_eras[1:]:
128 strategy = e0.overlapping(e1)
129 if strategy > 0:
130 self.all_eras.append(overlap_func[strategy](e0, e1))
131 self.all_eras = sorted(self.all_eras, key=get_key)
132 return False
133 else:
134 e0 = e1
135 return True
136
137 def adjust_all_eras_for_ends_today():
138 for era in self.all_eras:
139 if era.ends_today():
140 era.set_time_period(TimePeriod(era.get_time_period().start_time, self.now_func()))
141
142 self.all_eras = clone_all_eras()
143 adjust_all_eras_for_ends_today()
144 if self.all_eras == []:
145 return []
146 while True:
147 if len(self.all_eras) > 0:
148 done = create_overlapping_era_and_remove_hidden_eras()
149 else:
150 done = True
151 if done:
152 return self.all_eras
153