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, 2012, 2013, 2014, 2015, 2016, 2017, 2018  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  from timelinelib.canvas.data.subevent import Subevent 
 21   
 22   
23 -class DefaultContainerStrategy(ContainerStrategy):
24
25 - def __init__(self, container):
27
28 - def register_subevent(self, subevent):
29 if not isinstance(subevent, Subevent): 30 raise TypeError("Expected Subevent object") 31 if self._is_subevent_missing(subevent): 32 self._append_subevent(subevent) 33 if len(self.container.subevents) != 1: 34 self._adjust_time_period(subevent)
35
36 - def _append_subevent(self, subevent):
37 self.container.subevents.append(subevent) 38 self._sort_subevents()
39
40 - def _sort_subevents(self):
41 without_sort_order = [] 42 with_sort_order = [] 43 for subevent in self.container.subevents: 44 if subevent.sort_order is None: 45 without_sort_order.append(subevent) 46 else: 47 with_sort_order.append(subevent) 48 self.container.subevents = sorted( 49 with_sort_order, 50 key=lambda subevent: subevent.sort_order 51 ) + without_sort_order
52
53 - def unregister_subevent(self, subevent):
54 if self._is_subevent_missing(subevent): 55 return 56 self.container.subevents.remove(subevent)
57
58 - def update(self, subevent):
61
63 return False
64
65 - def _adjust_time_period(self, new_event):
66 """ 67 If the event to be added to the container overlaps any other 68 event in the container or if the new event is outside of the 69 container time period the container time period must be adjusted. 70 """ 71 event = self._event_totally_overlapping_new_event(new_event) 72 if event is not None: 73 self._adjust_when_new_event_is_totally_overlapped(new_event, event) 74 else: 75 events = self._events_overlapped_by_new_event(new_event) 76 if len(events) > 0: 77 self._adjust_when_new_event_partially_overlaps_other_events(new_event, events)
78
79 - def _adjust_when_new_event_is_totally_overlapped(self, new_event, event):
80 # Situation: 81 # event: +--------------------------------------------+ 82 # new_event: +-------------+ 83 # |- left_delta -| |- right_delta -| 84 # 85 # or +----------+ 86 # or +-------------------+ 87 # or +--------------------------------------------+ 88 # or + 89 # or + 90 # or + 91 left_delta = event.start_to_start(new_event).delta() 92 right_delta = new_event.end_to_end(event).delta() 93 if left_delta > right_delta: 94 self._move_events_left(new_event, event) 95 else: 96 self._move_events_right(new_event, event)
97
98 - def _move_events_left(self, new_event, event):
99 delta = new_event.start_to_end(event).delta() 100 latest_start_time = event.get_time_period().start_time 101 self._move_early_events_left(new_event, latest_start_time, delta)
102
103 - def _move_events_right(self, new_event, event):
104 delta = event.start_to_end(new_event).delta() 105 earliest_start_time = event.get_time_period().start_time 106 self._move_late_events_right(new_event, earliest_start_time, delta)
107
109 # Situation: 110 # V = threshold_time 111 # |-td-| 112 # new_event: +----------------------+ 113 # events: +-------------+ 114 # or +-------------+ 115 # or +-------------+ 116 # or +-------------+ 117 # or +-------------+ 118 threshold_time = self._calc_threshold_time(new_event) 119 event = self._some_event_in_new_event_threshold_time(new_event, 120 events, 121 threshold_time) 122 if event is not None: 123 self._adjust_threshold_triggered_events(new_event, event, threshold_time) 124 earliest_start = self._earliest_start_time_for_event_that_starts_within_new_event(new_event, 125 events, 126 threshold_time) 127 if earliest_start is not None: 128 self._adjust_events_starting_in_new_event(new_event, earliest_start)
129
130 - def _calc_threshold_time(self, new_event):
131 td = new_event.time_span() * 0.2 132 threshold_time = new_event.get_time_period().start_time + td 133 return threshold_time
134
135 - def _some_event_in_new_event_threshold_time(self, new_event, events, end):
136 start = new_event.get_time_period().start_time 137 for event in events: 138 if event is new_event: 139 continue 140 if (event.get_time_period().end_time >= start and event.get_time_period().end_time <= end): 141 return event 142 if (event.get_time_period().start_time <= start and event.get_time_period().end_time > end): 143 return event 144 return None
145
146 - def _adjust_threshold_triggered_events(self, new_event, event, threshold_time):
147 delta = event.get_time_period().end_time - new_event.get_time_period().start_time 148 self._move_early_events_left(new_event, threshold_time, delta)
149
150 - def _earliest_start_time_for_event_that_starts_within_new_event(self, new_event, events, thr):
151 start = new_event.get_time_period().start_time 152 end = new_event.get_time_period().end_time 153 min_start = None 154 for event in events: 155 if not event.is_period(): 156 if event.get_time_period().start_time < thr: 157 continue 158 if (event.get_time_period().start_time >= start and event.get_time_period().start_time <= end): 159 if min_start is None: 160 min_start = event.get_time_period().start_time 161 else: 162 if event.get_time_period().start_time < min_start: 163 min_start = event.get_time_period().start_time 164 return min_start
165
166 - def _adjust_events_starting_in_new_event(self, new_event, earliest_start):
167 delta = new_event.get_time_period().end_time - earliest_start 168 self._move_late_events_right(new_event, earliest_start, delta)
169
170 - def _event_totally_overlapping_new_event(self, new_event):
171 for event in self.container.subevents: 172 if event is new_event: 173 continue 174 if (self._event_totally_overlaps_new_event(new_event, event)): 175 return event 176 return None
177
178 - def _event_totally_overlaps_new_event(self, new_event, event):
181
182 - def _events_overlapped_by_new_event(self, new_event):
183 overlapping_events = [] 184 for event in self.container.subevents: 185 if event is not new_event: 186 if (self._starts_within(event, new_event) or self._ends_within(event, new_event)): 187 overlapping_events.append(event) 188 return overlapping_events
189
190 - def _starts_within(self, event, new_event):
194
195 - def _ends_within(self, event, new_event):
199
200 - def _move_early_events_left(self, new_event, latest_start_time, delta):
201 delta = -delta 202 for event in self.container.subevents: 203 if event is new_event: 204 continue 205 if event.get_time_period().start_time <= latest_start_time: 206 event.move_delta(delta)
207
208 - def _move_late_events_right(self, new_event, earliest_start_time, delta):
209 for event in self.container.subevents: 210 if event is new_event: 211 continue 212 if event.get_time_period().start_time >= earliest_start_time: 213 event.move_delta(delta)
214
215 - def _is_subevent_missing(self, subevent):
216 for x in self.container.subevents: 217 if x is subevent: 218 return False 219 return True
220 221
222 -class ExtendedContainerStrategy(DefaultContainerStrategy):
223
224 - def register_subevent(self, subevent):
225 if not isinstance(subevent, Subevent): 226 raise TypeError("Expected Subevent object") 227 if self._is_subevent_missing(subevent): 228 self._append_subevent(subevent)
229
231 return True
232