Package Gnumed :: Package timelinelib :: Package canvas :: Package data :: Module timeperiod |
[frames] | no frames]

# Source Code for Module Gnumed.timelinelib.canvas.data.timeperiod

      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  from timelinelib.calendar.gregorian.gregorian import GregorianDateTime
     18
     19
     20 -class TimePeriod(object):
     21
     22      """
     23      Represents a period in time using a start and end time.
     24
     25      This is used both to store the time period for an event and for storing the
     26      currently displayed time period in the GUI.
     27      """
     28
     29 -    def __init__(self, start_time, end_time):
     30          self._start_time, self._end_time = self._update(start_time, end_time)
     31
     32      @property
     33 -    def start_time(self):
     34          return self._start_time
     35
     36      @property
     37 -    def end_time(self):
     38          return self._end_time
     39
     40      @property
     41 -    def start_and_end_time(self):
     42          return self._start_time, self._end_time
     43
     44 -    def __eq__(self, other):
     45          return (isinstance(other, TimePeriod) and
     46                  self.start_time == other.start_time and
     47                  self.end_time == other.end_time)
     48
     49 -    def __ne__(self, other):
     50          return not (self == other)
     51
     52 -    def __repr__(self):
     53          return "TimePeriod<%s, %s>" % (self.start_time, self.end_time)
     54
     55 -    def get_time_at_percent(self, percent):
     56          return self.start_time + self.delta() * percent
     57
     58 -    def get_start_time(self):
     59          return self.start_time
     60
     61 -    def get_end_time(self):
     62          return self.end_time
     63
     64 -    def set_start_time(self, time):
     65          return self.update(time, self.end_time)
     66
     67 -    def set_end_time(self, time):
     68          return self.update(self.start_time, time)
     69
     70 -    def start_to_start(self, time_period):
     71          return TimePeriod(self.start_time, time_period.get_start_time())
     72
     73 -    def start_to_end(self, time_period):
     74          return TimePeriod(self.start_time, time_period.get_end_time())
     75
     76 -    def end_to_start(self, time_period):
     77          return TimePeriod(self.end_time, time_period.get_start_time())
     78
     79 -    def end_to_end(self, time_period):
     80          return TimePeriod(self.end_time, time_period.get_end_time())
     81
     82 -    def update(self, start_time, end_time,
     83                 start_delta=None, end_delta=None):
     84          new_start, new_end = self._update(start_time, end_time, start_delta, end_delta)
     85          return TimePeriod(new_start, new_end)
     86
     87 -    def _update(self, start_time, end_time, start_delta=None, end_delta=None):
     88          """
     89          Change the time period data.
     90
     91          Optionally add the deltas to the times like this: time + delta.
     92
     93          If data is invalid, it will not be set, and a ValueError will be raised
     94          instead. Data is invalid if or if the start time is larger than the end
     95          time.
     96          """
     97          new_start = self._calc_new_time(start_time, start_delta)
     98          new_end = self._calc_new_time(end_time, end_delta)
     99          self._assert_period_is_valid(new_start, new_end)
    100          return (new_start, new_end)
    101
    102 -    def _assert_period_is_valid(self, new_start, new_end):
    103          if new_start is None:
    104              raise ValueError(_("Invalid start time"))
    105          if new_end is None:
    106              raise ValueError(_("Invalid end time"))
    107          if new_start > new_end:
    108              raise ValueError(_("Start time can't be after end time. Start:%s End:%s" %
    109                                 (GregorianDateTime.from_time(new_start),
    110                                  GregorianDateTime.from_time(new_end))))
    111
    112 -    def inside(self, time):
    113          """
    114          Return True if the given time is inside this period or on the border,
    115          otherwise False.
    116          """
    117          return time >= self.start_time and time <= self.end_time
    118
    119 -    def distance_to(self, time_period):
    120          if time_period.starts_after(self.end_time):
    121              return self.end_to_start(time_period).delta()
    122          elif time_period.ends_before(self.start_time):
    123              return time_period.end_to_start(self).delta()
    124          else:
    125              return None
    126
    127 -    def overlaps(self, time_period):
    128          return (time_period.ends_after(self.start_time) and
    129                  time_period.starts_before(self.end_time))
    130
    131 -    def outside_period(self, time_period):
    132          return (time_period.ends_before(self.start_time) or
    133                  time_period.starts_after(self.end_time))
    134
    135 -    def inside_period(self, time_period):
    136          return not self.outside_period(time_period)
    137
    138 -    def starts_after(self, time):
    139          return self.start_time > time
    140
    141 -    def starts_before(self, time):
    142          return self.start_time < time
    143
    144 -    def ends_before(self, time):
    145          return self.end_time < time
    146
    147 -    def ends_after(self, time):
    148          return self.end_time > time
    149
    150 -    def ends_at(self, time):
    151          return self.end_time == time
    152
    153 -    def is_period(self):
    154          """
    155          Return True if this time period is longer than just a point in time,
    156          otherwise False.
    157          """
    158          return self.start_time != self.end_time
    159
    160 -    def mean_time(self):
    161          """
    162          Return the time in the middle if this time period is longer than just a
    163          point in time, otherwise the point in time for this time period.
    164          """
    165          return self.start_time + (self.delta() / 2)
    166
    167 -    def zoom(self, times, ratio=0.5):
    168          start_delta = self.delta() * (times * ratio / 5.0)
    169          end_delta = self.delta() * (-times * (1.0 - ratio) / 5.0)
    170          return self.update(self.start_time, self.end_time, start_delta, end_delta)
    171
    172 -    def move(self, direction):
    173          """
    174          Move this time period one 10th to the given direction.
    175
    176          Direction should be -1 for moving to the left or 1 for moving to the
    177          right.
    178          """
    179          delta = self.delta() * (direction / 10.0)
    180          return self.move_delta(delta)
    181
    182 -    def move_delta(self, delta):
    183          return self.update(self.start_time, self.end_time, delta, delta)
    184
    185 -    def delta(self):
    186          """Return the length of this time period as a timedelta object."""
    187          return self.end_time - self.start_time
    188
    189 -    def center(self, time):
    190          return self.move_delta(time - self.mean_time())
    191
    192 -    def _calc_new_time(self, time, delta):
    193          if delta is None:
    194              return time
    195          return time + delta
    196
    197
    198 -class TimeOutOfRangeLeftError(ValueError):
    199      pass
    200
    201
    202 -class TimeOutOfRangeRightError(ValueError):
    203      pass
    204
    205
    206 -def time_period_center(time, length):
    207      """
    208      TimePeriod factory method.
    209
    210      Return a time period with the given length (represented as a timedelta)
    211      centered around `time`.
    212      """
    213      half_length = length * 0.5
    214      start_time = time - half_length
    215      end_time = time + half_length
    216      return TimePeriod(start_time, end_time)
    217