Package Gnumed :: Package timelinelib :: Package db :: Module strategies
[frames] | no frames]

Source Code for Module Gnumed.timelinelib.db.strategies

  1  # Copyright (C) 2009, 2010, 2011  Rickard Lindberg, Roger Lindberg 
  2  # 
  3  # This file is part of Timeline. 
  4  # 
  5  # Timeline is free software: you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation, either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Timeline is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with Timeline.  If not, see <http://www.gnu.org/licenses/>. 
 17   
 18   
 19  from timelinelib.db.interface import ContainerStrategy 
 20   
 21   
22 -class DefaultContainerStrategy(ContainerStrategy):
23
24 - def __init__(self, container):
26
27 - def register_subevent(self, subevent):
28 if subevent not in self.container.events: 29 self.container.events.append(subevent) 30 subevent.register_container(self.container) 31 if len(self.container.events) == 1: 32 self._set_time_period() 33 else: 34 self._adjust_time_period(subevent)
35
36 - def unregister_subevent(self, subevent):
37 if subevent not in self.container.events: 38 return 39 self.container.events.remove(subevent) 40 self._set_time_period()
41
42 - def update(self, subevent):
43 self.unregister_subevent(subevent) 44 self.register_subevent(subevent) 45 self._set_time_period()
46
47 - def _set_time_period(self):
48 """ 49 The container time period starts where the subevent with the earliest 50 start time, starts, and it ends where the subevent whith the latest end 51 time ends. 52 Subevents +------+ +--------+ +--+ 53 Container +--------------------------+ 54 """ 55 if len(self.container.events) == 0: 56 return 57 self._set_start_time(self.container.events[0]) 58 self._set_end_time(self.container.events[0]) 59 for event in self.container.events: 60 if self._container_starts_after_event(event): 61 self._set_start_time(event) 62 if self._container_ends_before_event(event): 63 self._set_end_time(event)
64
65 - def _container_starts_after_event(self, subevent):
66 return (self.container.time_period.start_time > 67 subevent.time_period.start_time)
68
69 - def _container_ends_before_event(self, event):
70 return (self.container.time_period.end_time < 71 event.time_period.end_time)
72
73 - def _set_start_time(self, event):
74 self.container.time_period.start_time = event.time_period.start_time
75
76 - def _set_end_time(self, event):
77 self.container.time_period.end_time = event.time_period.end_time
78
79 - def _adjust_time_period(self, new_event):
80 """ 81 If the event to be added to the container overlaps any other 82 event in the container or if the new event is outside of the 83 container time period the container time period must be adjusted. 84 """ 85 event = self._event_totally_overlapping_new_event(new_event) 86 if event is not None: 87 self._adjust_when_new_event_is_totally_overlapped(new_event, event) 88 else: 89 events = self._events_overlapped_by_new_event(new_event) 90 if len(events) > 0: 91 self._adjust_when_new_event_partially_overlaps_other_events(new_event, events) 92 self._set_time_period()
93
94 - def _adjust_when_new_event_is_totally_overlapped(self, new_event, event):
95 # Situation: 96 # event: +--------------------------------------------+ 97 # new_event: +-------------+ 98 # |- left_delta -| |- right_delta -| 99 # 100 # or +----------+ 101 # or +-------------------+ 102 # or +--------------------------------------------+ 103 # or + 104 # or + 105 # or + 106 left_delta = new_event.time_period.start_time - event.time_period.start_time 107 right_delta = event.time_period.end_time - new_event.time_period.end_time 108 move_left = left_delta > right_delta 109 if move_left: 110 self._move_events_left(new_event, event) 111 else: 112 self._move_events_right(new_event, event)
113
114 - def _move_events_left(self, new_event, event):
115 delta = event.time_period.end_time - new_event.time_period.start_time 116 latest_start_time = event.time_period.start_time 117 self._move_early_events_left(new_event, latest_start_time, delta)
118
119 - def _move_events_right(self, new_event, event):
120 delta = new_event.time_period.end_time - event.time_period.start_time 121 earliest_start_time = event.time_period.start_time 122 self._move_late_events_right(new_event, earliest_start_time, delta)
123
125 # Situation: 126 # V = threshold_time 127 # |-td-| 128 # new_event: +----------------------+ 129 # events: +-------------+ 130 # or +-------------+ 131 # or +-------------+ 132 # or +-------------+ 133 # or +-------------+ 134 threshold_time = self._calc_threshold_time(new_event) 135 event = self._some_event_in_new_event_threshold_time(new_event, 136 events, 137 threshold_time) 138 if event is not None: 139 self._adjust_threshold_triggered_events(new_event, event, threshold_time) 140 earliest_start = self._earliest_start_time_for_event_that_starts_within_new_event(new_event, 141 events, 142 threshold_time) 143 if earliest_start is not None: 144 self._adjust_events_starting_in_new_event(new_event, earliest_start)
145
146 - def _calc_threshold_time(self, new_event):
147 td = new_event.time_span() 148 td = new_event.time_type.mult_timedelta(td, 0.2) 149 threshold_time = new_event.time_period.start_time + td 150 return threshold_time
151
152 - def _some_event_in_new_event_threshold_time(self, new_event, events, end):
153 start = new_event.time_period.start_time 154 for event in events: 155 if event == new_event: 156 continue 157 if event.time_period.end_time >= start and event.time_period.end_time <= end: 158 return event 159 if event.time_period.start_time <= start and event.time_period.end_time > end: 160 return event 161 return None
162
163 - def _adjust_threshold_triggered_events(self, new_event, event, threshold_time):
164 delta = event.time_period.end_time - new_event.time_period.start_time 165 self._move_early_events_left(new_event, threshold_time, delta)
166
167 - def _earliest_start_time_for_event_that_starts_within_new_event(self, new_event, events, thr):
168 start = new_event.time_period.start_time 169 end = new_event.time_period.end_time 170 min_start = None 171 for event in events: 172 if not event.is_period(): 173 if event.time_period.start_time < thr: 174 continue 175 if event.time_period.start_time >= start and event.time_period.start_time <= end: 176 if min_start == None: 177 min_start = event.time_period.start_time 178 else: 179 if event.time_period.start_time < min_start: 180 min_start = event.time_period.start_time 181 return min_start
182
183 - def _adjust_events_starting_in_new_event(self, new_event, earliest_start):
184 delta = new_event.time_period.end_time - earliest_start 185 self._move_late_events_right(new_event, earliest_start, delta)
186
187 - def _event_totally_overlapping_new_event(self, new_event):
188 for event in self.container.events: 189 if event == new_event: 190 continue 191 if (self._event_totally_overlaps_new_event(new_event, event)): 192 return event 193 return None
194
195 - def _event_totally_overlaps_new_event(self, new_event, event):
196 return (event.time_period.start_time <= new_event.time_period.start_time and 197 event.time_period.end_time >= new_event.time_period.end_time)
198
199 - def _events_overlapped_by_new_event(self, new_event):
200 overlapping_events = [] 201 for event in self.container.events: 202 if event != new_event: 203 if (self._starts_within(event, new_event) or 204 self._ends_within(event, new_event)): 205 overlapping_events.append(event) 206 return overlapping_events
207
208 - def _starts_within(self, event, new_event):
209 s1 = event.time_period.start_time >= new_event.time_period.start_time 210 s2 = event.time_period.start_time <= new_event.time_period.end_time 211 return (s1 and s2)
212
213 - def _ends_within(self, event, new_event):
214 s1 = event.time_period.end_time >= new_event.time_period.start_time 215 s2 = event.time_period.end_time <= new_event.time_period.end_time 216 return (s1 and s2)
217
218 - def _move_early_events_left(self, new_event, latest_start_time, delta):
219 delta = -delta 220 for event in self.container.events: 221 if event == new_event: 222 continue 223 if event.time_period.start_time <= latest_start_time: 224 self._adjust_event_time_period(event, delta)
225
226 - def _move_late_events_right(self, new_event, earliest_start_time, delta):
227 for event in self.container.events: 228 if event == new_event: 229 continue 230 if event.time_period.start_time >= earliest_start_time: 231 self._adjust_event_time_period(event, delta)
232
233 - def _adjust_event_time_period(self, event, delta):
234 new_start = event.time_period.start_time + delta 235 new_end = event.time_period.end_time + delta 236 event.time_period.start_time = new_start 237 event.time_period.end_time = new_end
238