Package Gnumed :: Package timelinelib :: Package db :: Package objects :: Module timeperiod
[frames] | no frames]

Source Code for Module Gnumed.timelinelib.db.objects.timeperiod

  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 -class TimePeriod(object):
20 """ 21 Represents a period in time using a start and end time. 22 23 This is used both to store the time period for an event and for storing the 24 currently displayed time period in the GUI. 25 """ 26
27 - def __init__(self, time_type, start_time, end_time):
28 """ 29 Create a time period. 30 31 `start_time` and `end_time` should be of a type that can be handled 32 by the time_type object. 33 """ 34 self.time_type = time_type 35 self.start_time, self.end_time = self._update(start_time, end_time)
36
37 - def clone(self):
38 return TimePeriod(self.time_type, self.start_time, self.end_time)
39
40 - def __eq__(self, other):
41 if isinstance(other, TimePeriod): 42 return (self.start_time == other.start_time and 43 self.end_time == other.end_time) 44 return False
45
46 - def __ne__(self, other):
47 return not (self == other)
48
49 - def __repr__(self):
50 return "TimePeriod<%s, %s>" % (self.start_time, self.end_time)
51
52 - def update(self, start_time, end_time, 53 start_delta=None, end_delta=None):
54 new_start, new_end = self._update(start_time, end_time, start_delta, end_delta) 55 return TimePeriod(self.time_type, new_start, new_end)
56
57 - def _update(self, start_time, end_time, 58 start_delta=None, end_delta=None):
59 """ 60 Change the time period data. 61 62 Optionally add the deltas to the times like this: time + delta. 63 64 If data is invalid, it will not be set, and a ValueError will be raised 65 instead. 66 67 Data is invalid if time + delta is not within the range 68 [self.time_type.get_min_time(), self.time_type.get_max_time()] or if 69 the start time is larger than the end time. 70 """ 71 new_start = self._ensure_within_range(start_time, start_delta, 72 _("Start time ")) 73 new_end = self._ensure_within_range(end_time, end_delta, 74 _("End time ")) 75 self._assert_period_is_valid(new_start, new_end) 76 return (new_start, new_end)
77
78 - def _assert_period_is_valid(self, new_start, new_end):
79 self._assert_start_gt_end(new_start, new_end) 80 self._assert_period_lt_max(new_start, new_end)
81
82 - def _assert_start_gt_end(self, new_start, new_end):
83 if new_start > new_end: 84 raise ValueError(_("Start time can't be after end time"))
85
86 - def _assert_period_lt_max(self, new_start, new_end):
87 MAX_ZOOM_DELTA, max_zoom_error_text = self.time_type.get_max_zoom_delta() 88 if MAX_ZOOM_DELTA and (new_end - new_start > MAX_ZOOM_DELTA): 89 raise PeriodTooLongError(max_zoom_error_text)
90
91 - def inside(self, time):
92 """ 93 Return True if the given time is inside this period or on the border, 94 otherwise False. 95 """ 96 return time >= self.start_time and time <= self.end_time
97
98 - def overlap(self, time_period):
99 """Return True if this time period has any overlap with the given.""" 100 return not (time_period.end_time < self.start_time or 101 time_period.start_time > self.end_time)
102
103 - def is_period(self):
104 """ 105 Return True if this time period is longer than just a point in time, 106 otherwise False. 107 """ 108 return self.start_time != self.end_time
109
110 - def mean_time(self):
111 """ 112 Return the time in the middle if this time period is longer than just a 113 point in time, otherwise the point in time for this time period. 114 """ 115 return self.start_time + self.time_type.half_delta(self.delta())
116
117 - def zoom(self, times, ratio=0.5):
118 MAX_ZOOM_DELTA, max_zoom_error_text = self.time_type.get_max_zoom_delta() 119 MIN_ZOOM_DELTA, min_zoom_error_text = self.time_type.get_min_zoom_delta() 120 start_delta = self.time_type.mult_timedelta(self.delta(), times * ratio / 5.0) 121 end_delta = self.time_type.mult_timedelta(self.delta(), -times * (1.0 - ratio) / 5.0) 122 new_delta = self.delta() - 2 * start_delta 123 if MAX_ZOOM_DELTA and new_delta > MAX_ZOOM_DELTA: 124 raise ValueError(max_zoom_error_text) 125 if new_delta < MIN_ZOOM_DELTA: 126 raise ValueError(min_zoom_error_text) 127 return self.update(self.start_time, self.end_time, start_delta, end_delta)
128
129 - def move(self, direction):
130 """ 131 Move this time period one 10th to the given direction. 132 133 Direction should be -1 for moving to the left or 1 for moving to the 134 right. 135 """ 136 delta = self.time_type.mult_timedelta(self.delta(), direction / 10.0) 137 return self.move_delta(delta)
138
139 - def move_delta(self, delta):
140 return self.update(self.start_time, self.end_time, delta, delta)
141
142 - def delta(self):
143 """Return the length of this time period as a timedelta object.""" 144 return self.end_time - self.start_time
145
146 - def center(self, time):
147 """ 148 Center time period around time keeping the length. 149 150 If we can't center because we are on the edge, we do as good as we can. 151 """ 152 delta = time - self.mean_time() 153 start_overflow = self._calculate_overflow(self.start_time, delta)[1] 154 end_overflow = self._calculate_overflow(self.end_time, delta)[1] 155 if start_overflow == -1: 156 delta = self.time_type.get_min_time()[0] - self.start_time 157 elif end_overflow == 1: 158 delta = self.time_type.get_max_time()[0] - self.end_time 159 return self.move_delta(delta)
160
161 - def _ensure_within_range(self, time, delta, error_prefix):
162 """ 163 Return new time (time + delta) or raise ValueError if it is not within 164 the range [self.time_type.get_min_time(), 165 self.time_type.get_max_time()]. 166 """ 167 if delta == None: 168 delta = self.time_type.get_zero_delta() 169 new_time, overflow, error_text = self._calculate_overflow(time, delta) 170 if overflow != 0: 171 error_text = "%s %s" % (error_prefix, error_text) 172 raise ValueError(error_text) 173 else: 174 return new_time
175
176 - def _calculate_overflow(self, time, delta):
177 """ 178 Return a tuple (new time, overflow flag). 179 180 Overflow flag can be -1 (overflow to the left), 0 (no overflow), or 1 181 (overflow to the right). 182 183 If overflow flag is 0 new time is time + delta, otherwise None. 184 """ 185 try: 186 min_time, min_error_text = self.time_type.get_min_time() 187 max_time, max_error_text = self.time_type.get_max_time() 188 new_time = time + delta 189 if min_time and new_time < min_time: 190 return (None, -1, min_error_text) 191 if max_time and new_time > max_time: 192 return (None, 1, max_error_text) 193 return (new_time, 0, "") 194 except OverflowError: 195 if delta > self.time_type.get_zero_delta(): 196 return (None, 1, max_error_text) 197 else: 198 return (None, -1, min_error_text)
199
200 - def get_label(self):
201 """Returns a unicode string describing the time period.""" 202 return self.time_type.format_period(self)
203
204 - def has_nonzero_time(self):
205 return self.time_type.time_period_has_nonzero_time(self)
206 207
208 -class TimeOutOfRangeLeftError(ValueError):
209 pass
210 211
212 -class TimeOutOfRangeRightError(ValueError):
213 pass
214 215
216 -class PeriodTooLongError(ValueError):
217 pass
218 219
220 -def time_period_center(time_type, time, length):
221 """ 222 TimePeriod factory method. 223 224 Return a time period with the given length (represented as a timedelta) 225 centered around `time`. 226 """ 227 half_length = time_type.mult_timedelta(length, 0.5) 228 start_time = time - half_length 229 end_time = time + half_length 230 return TimePeriod(time_type, start_time, end_time)
231