Gnumed.timelinelib.canvas.data.timeperiod

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