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 (
47 (c1[0] + c2[0]) // 2,
48 (c1[1] + c2[1]) // 2,
49 (c1[2] + c2[2]) // 2
50 )
51
52 def create_overlapping_era(e0, e1, start, end):
53 era = e1.duplicate()
54 era.set_time_period(TimePeriod(start, end))
55 era.set_color(merge_colors(e0.get_color(), e1.get_color()))
56 era.set_name("%s + %s" % (e0.get_name(), e1.get_name()))
57 return era
58
59 def get_start_and_end_times(e0, e1):
60 e0start = e0.get_time_period().start_time
61 e0end = e0.get_time_period().end_time
62 e1start = e1.get_time_period().start_time
63 e1end = e1.get_time_period().end_time
64 return e0start, e0end, e1start, e1end
65
66 def return_era_for_overlapping_type_1(e0, e1):
67 e0start, e0end, e1start, e1end = get_start_and_end_times(e0, e1)
68 era = create_overlapping_era(e0, e1, e1start, e0end)
69 e0.set_time_period(TimePeriod(e0start, e1start))
70 e1.set_time_period(TimePeriod(e0end, e1end))
71 return era
72
73 def return_era_for_overlapping_type_2(e0, e1):
74 e0start, e0end, _, e1end = get_start_and_end_times(e0, e1)
75 era = create_overlapping_era(e0, e1, e0start, e0end)
76 self.all_eras.remove(e0)
77 e1.set_time_period(TimePeriod(e0end, e1end))
78 return era
79
80 def return_era_for_overlapping_type_3(e0, e1):
81 return return_era_for_overlapping_type_2(e1, e0)
82
83 def return_era_for_overlapping_type_4(e0, e1):
84 _, _, e1start, e1end = get_start_and_end_times(e0, e1)
85 era = create_overlapping_era(e0, e1, e1start, e1end)
86 self.all_eras.remove(e0)
87 self.all_eras.remove(e1)
88 return era
89
90 def return_era_for_overlapping_type_5(e0, e1):
91 e0start, _, e1start, e1end = get_start_and_end_times(e0, e1)
92 era = create_overlapping_era(e0, e1, e1start, e1end)
93 e0.set_time_period(TimePeriod(e0start, e1start))
94 self.all_eras.remove(e1)
95 return era
96
97 def return_era_for_overlapping_type_6(e0, e1):
98 e0start, e0end, e1start, e1end = get_start_and_end_times(e0, e1)
99 era = create_overlapping_era(e0, e1, e1start, e1end)
100 e0.set_time_period(TimePeriod(e0start, e1start))
101 e1.set_time_period(TimePeriod(e1end, e0end))
102 e1.set_name(e0.get_name())
103 e1.set_color(e0.get_color())
104 return era
105
106 def clone_all_eras():
107 return [e.duplicate() for e in self.get_all()]
108
109 overlap_func = (None,
110 return_era_for_overlapping_type_1,
111 return_era_for_overlapping_type_2,
112 return_era_for_overlapping_type_3,
113 return_era_for_overlapping_type_4,
114 return_era_for_overlapping_type_5,
115 return_era_for_overlapping_type_6)
116
117 def create_overlapping_era_and_remove_hidden_eras():
118 """
119 self.all_eras is always sorted by Era start time.
120 This method finds the first pair of Era's that overlaps.
121 If such a pair is found, a overlapping Era is created and added
122 to the the self.all_eras list. If any or both of the original
123 Era's are hidden by the overlapping Era, they are removed from
124 the self.all_eras list.
125 When one overlapping pair has been found and processed the
126 function returns False, after updating the self.all_eras list
127 If no overlapping pairs of Era's are found the function retuns
128 True.
129 """
130 e0 = self.all_eras[0]
131 for e1 in self.all_eras[1:]:
132 strategy = e0.overlapping(e1)
133 if strategy > 0:
134 self.all_eras.append(overlap_func[strategy](e0, e1))
135 self.all_eras = sorted(self.all_eras, key=get_key)
136 return False
137 else:
138 e0 = e1
139 return True
140
141 def adjust_all_eras_for_ends_today():
142 for era in self.all_eras:
143 if era.ends_today():
144 era.set_time_period(TimePeriod(era.get_time_period().start_time, self.now_func()))
145
146 self.all_eras = clone_all_eras()
147 adjust_all_eras_for_ends_today()
148 if self.all_eras == []:
149 return []
150 while True:
151 if len(self.all_eras) > 0:
152 done = create_overlapping_era_and_remove_hidden_eras()
153 else:
154 done = True
155 if done:
156 return self.all_eras
157