Gnumed.timelinelib.canvas.data.eras

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

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

      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.canvas.data.timeperiod import TimePeriod
     20
     21
     22 -class Eras(object):
     23      """
     24      The list of all eras defined for a timeline.
     25
     26      Contains function for cloning of the whole list which is a
     27      necessary operation for undo/redo operations.
     28      """
     29
     30 -    def __init__(self, now_func, eras=None):
     31          self.now_func = now_func
     32          if eras is None:
     33              self._eras = []
     34          else:
     35              self._eras = eras
     36
     37 -    def get_all(self):
     38          return sorted(self._eras)
     39
     40 -    def get_all_periods(self):
     41
     42          def get_key(e):
     43              return e.get_time_period().start_time
     44
     45          def merge_colors(c1, c2):
     46              return (
     47                  (c1[0] + c2[0]) // 2,
     48                  (c1[1] + c2[1]) // 2,
     49                  (c1[2] + c2[2]) // 2
     50              )
     51
     52          def create_overlapping_era(e0, e1, start, end):
     53              era = e1.duplicate()
     54              era.set_time_period(TimePeriod(start, end))
     55              era.set_color(merge_colors(e0.get_color(), e1.get_color()))
     56              era.set_name("%s + %s" % (e0.get_name(), e1.get_name()))
     57              return era
     58
     59          def get_start_and_end_times(e0, e1):
     60              e0start = e0.get_time_period().start_time
     61              e0end = e0.get_time_period().end_time
     62              e1start = e1.get_time_period().start_time
     63              e1end = e1.get_time_period().end_time
     64              return e0start, e0end, e1start, e1end
     65
     66          def return_era_for_overlapping_type_1(e0, e1):
     67              e0start, e0end, e1start, e1end = get_start_and_end_times(e0, e1)
     68              era = create_overlapping_era(e0, e1, e1start, e0end)
     69              e0.set_time_period(TimePeriod(e0start, e1start))
     70              e1.set_time_period(TimePeriod(e0end, e1end))
     71              return era
     72
     73          def return_era_for_overlapping_type_2(e0, e1):
     74              e0start, e0end, _, e1end = get_start_and_end_times(e0, e1)
     75              era = create_overlapping_era(e0, e1, e0start, e0end)
     76              self.all_eras.remove(e0)
     77              e1.set_time_period(TimePeriod(e0end, e1end))
     78              return era
     79
     80          def return_era_for_overlapping_type_3(e0, e1):
     81              return return_era_for_overlapping_type_2(e1, e0)
     82
     83          def return_era_for_overlapping_type_4(e0, e1):
     84              _, _, e1start, e1end = get_start_and_end_times(e0, e1)
     85              era = create_overlapping_era(e0, e1, e1start, e1end)
     86              self.all_eras.remove(e0)
     87              self.all_eras.remove(e1)
     88              return era
     89
     90          def return_era_for_overlapping_type_5(e0, e1):
     91              e0start, _, e1start, e1end = get_start_and_end_times(e0, e1)
     92              era = create_overlapping_era(e0, e1, e1start, e1end)
     93              e0.set_time_period(TimePeriod(e0start, e1start))
     94              self.all_eras.remove(e1)
     95              return era
     96
     97          def return_era_for_overlapping_type_6(e0, e1):
     98              e0start, e0end, e1start, e1end = get_start_and_end_times(e0, e1)
     99              era = create_overlapping_era(e0, e1, e1start, e1end)
    100              e0.set_time_period(TimePeriod(e0start, e1start))
    101              e1.set_time_period(TimePeriod(e1end, e0end))
    102              e1.set_name(e0.get_name())
    103              e1.set_color(e0.get_color())
    104              return era
    105
    106          def clone_all_eras():
    107              return [e.duplicate() for e in self.get_all()]
    108
    109          overlap_func = (None,
    110                          return_era_for_overlapping_type_1,
    111                          return_era_for_overlapping_type_2,
    112                          return_era_for_overlapping_type_3,
    113                          return_era_for_overlapping_type_4,
    114                          return_era_for_overlapping_type_5,
    115                          return_era_for_overlapping_type_6)
    116
    117          def create_overlapping_era_and_remove_hidden_eras():
    118              """
    119              self.all_eras is always sorted by Era start time.
    120              This method finds the first pair of Era's that overlaps.
    121              If such a pair is found, a overlapping Era is created and added
    122              to the the self.all_eras list. If any or both of the original
    123              Era's are hidden by the overlapping Era, they are removed from
    124              the self.all_eras list.
    125              When one overlapping pair has been found and processed the
    126              function returns False, after updating the self.all_eras list
    127              If no overlapping pairs of Era's are found the function retuns
    128              True.
    129              """
    130              e0 = self.all_eras[0]
    131              for e1 in self.all_eras[1:]:
    132                  strategy = e0.overlapping(e1)
    133                  if strategy > 0:
    134                      self.all_eras.append(overlap_func[strategy](e0, e1))
    135                      self.all_eras = sorted(self.all_eras, key=get_key)
    136                      return False
    137                  else:
    138                      e0 = e1
    139              return True
    140
    141          def adjust_all_eras_for_ends_today():
    142              for era in self.all_eras:
    143                  if era.ends_today():
    144                      era.set_time_period(TimePeriod(era.get_time_period().start_time, self.now_func()))
    145
    146          def remove_eras_with_no_duration():
    147              self.all_eras = [e for e in self.all_eras if e.is_period()]
    148
    149          self.all_eras = clone_all_eras()
    150          adjust_all_eras_for_ends_today()
    151          remove_eras_with_no_duration()
    152          if self.all_eras == []:
    153              return []
    154          while True:
    155              if len(self.all_eras) > 0:
    156                  done = create_overlapping_era_and_remove_hidden_eras()
    157              else:
    158                  done = True
    159              if done:
    160                  return self.all_eras
    161