Source code for timelinelib.calendar.bosparanian.timetype.timetype

# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Timeline is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Timeline.  If not, see <http://www.gnu.org/licenses/>.


import re

from timelinelib.calendar.bosparanian.bosparanian import BosparanianDateTime
from timelinelib.calendar.bosparanian.monthnames import bosp_abbreviated_name_of_month
from timelinelib.calendar.bosparanian.time import BosparanianDelta
from timelinelib.calendar.bosparanian.time import BosparanianTime
from timelinelib.calendar.gregorian.timetype.durationtype import DAYS
from timelinelib.calendar.gregorian.timetype import DurationFormatter
from timelinelib.calendar.gregorian.timetype.durationtype import HOURS
from timelinelib.calendar.gregorian.timetype.durationtype import MINUTES
from timelinelib.calendar.gregorian.timetype.durationtype import SECONDS
from timelinelib.calendar.gregorian.timetype import SECONDS_IN_DAY
from timelinelib.calendar.gregorian.timetype.durationtype import YEARS
from timelinelib.calendar.timetype import TimeType
from timelinelib.canvas.data import TimeOutOfRangeLeftError
from timelinelib.canvas.data import TimeOutOfRangeRightError
from timelinelib.canvas.data import TimePeriod
from timelinelib.canvas.data import time_period_center
from timelinelib.calendar.bosparanian.timetype.strips.stripcentury import StripCentury
from timelinelib.calendar.bosparanian.timetype.strips.stripdecade import StripDecade
from timelinelib.calendar.bosparanian.timetype.strips.stripquarter import StripQuarter
from timelinelib.calendar.bosparanian.timetype.strips.stripyear import StripYear
from timelinelib.calendar.bosparanian.timetype.strips.stripmonth import StripMonth
from timelinelib.calendar.bosparanian.timetype.strips.stripweek import StripWeek
from timelinelib.calendar.bosparanian.timetype.strips.stripweekday import StripWeekday
from timelinelib.calendar.bosparanian.timetype.strips.stripday import StripDay
from timelinelib.calendar.bosparanian.timetype.strips.striphour import StripHour
from timelinelib.calendar.bosparanian.timetype.strips.stripminute import StripMinute
from timelinelib.wxgui.dialogs.timeeditor.view import open_time_editor_dialog
from timelinelib.wxgui.dialogs.changenowdate.view import open_change_now_date_dialog


[docs]class BosparanianTimeType(TimeType): DURATION_TYPE_HOURS = _('Hours') DURATION_TYPE_WORKDAYS = _('Workdays') DURATION_TYPE_DAYS = _('Days') DURATION_TYPE_MINUTES = _('Minutes') DURATION_TYPE_SECONDS = _('Seconds')
[docs] def __init__(self): self.major_strip_is_decade = False self.saved_now = None
[docs] def __eq__(self, other): return isinstance(other, BosparanianTimeType)
[docs] def __ne__(self, other): return not (self == other)
[docs] def time_string(self, time): return "%d-%02d-%02d %02d:%02d:%02d" % BosparanianDateTime.from_time(time).to_tuple()
[docs] def parse_time(self, time_string): match = re.search(r"^(-?\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$", time_string) if match: year = int(match.group(1)) month = int(match.group(2)) day = int(match.group(3)) hour = int(match.group(4)) minute = int(match.group(5)) second = int(match.group(6)) try: return BosparanianDateTime(year, month, day, hour, minute, second).to_time() except ValueError: raise ValueError("Invalid time, time string = '%s'" % time_string) else: raise ValueError("Time not on correct format = '%s'" % time_string)
[docs] def get_navigation_functions(self): return [ (_("Open &Now Date Editor") + "\tCtrl+T", open_now_date_editor), (_("Go to &Date...") + "\tCtrl+G", go_to_date_fn), ("SEP", None), (_("Backward") + "\tPgUp", backward_fn), (_("Forward") + "\tPgDn", forward_fn), (_("Forward One Wee&k") + "\tCtrl+K", forward_one_week_fn), (_("Back One &Week") + "\tCtrl+W", backward_one_week_fn), (_("Forward One Mont&h") + "\tCtrl+H", forward_one_month_fn), (_("Back One &Month") + "\tCtrl+M", backward_one_month_fn), (_("Forward One Yea&r") + "\tCtrl+R", forward_one_year_fn), (_("Back One &Year") + "\tCtrl+Y", backward_one_year_fn), ("SEP", None), (_("Fit Millennium"), fit_millennium_fn), (_("Fit Century"), fit_century_fn), (_("Fit Decade"), fit_decade_fn), (_("Fit Year"), fit_year_fn), (_("Fit Month"), fit_month_fn), (_("Fit Week"), fit_week_fn), (_("Fit Day"), fit_day_fn), ("SEP", None), ]
[docs] def format_period(self, time_period): """Returns a unicode string describing the time period.""" def label_with_time(time): return "%s %s" % (label_without_time(time), time_label(time)) def label_without_time(time): bosparanian_datetime = BosparanianDateTime.from_time(time) return "%s %s %s" % (bosparanian_datetime.day, bosp_abbreviated_name_of_month(bosparanian_datetime.month), bosparanian_datetime.year) def time_label(time): return "%02d:%02d" % time.get_time_of_day()[:-1] if time_period.is_period(): if has_nonzero_time(time_period): label = "%s to %s" % (label_with_time(time_period.start_time), label_with_time(time_period.end_time)) else: label = "%s to %s" % (label_without_time(time_period.start_time), label_without_time(time_period.end_time)) else: if has_nonzero_time(time_period): label = "%s" % label_with_time(time_period.start_time) else: label = "%s" % label_without_time(time_period.start_time) return label
[docs] def format_delta(self, delta): days = abs(delta.get_days()) seconds = abs(delta.seconds) - days * SECONDS_IN_DAY delta_format = (YEARS, DAYS, HOURS, MINUTES, SECONDS) return DurationFormatter([days, seconds]).format(delta_format)
[docs] def get_min_time(self): return BosparanianTime.min()
[docs] def get_max_time(self): return BosparanianTime(5369833, 0)
[docs] def choose_strip(self, metrics, appearance): """ Return a tuple (major_strip, minor_strip) for current time period and window size. """ day_period = TimePeriod(BosparanianTime(0, 0), BosparanianTime(1, 0)) one_day_width = metrics.calc_exact_width(day_period) self.major_strip_is_decade = False if one_day_width > 20000: return StripHour(), StripMinute() elif one_day_width > 600: return StripDay(), StripHour() elif one_day_width > 60: return StripMonth(), StripWeekday() elif one_day_width > 25: return StripMonth(), StripDay() elif one_day_width > 10: return StripMonth(), StripWeek() elif one_day_width > 1.75: return StripYear(), StripMonth() elif one_day_width > 0.5: return StripYear(), StripQuarter() elif one_day_width > 0.12: self.major_strip_is_decade = True return StripDecade(), StripYear() elif one_day_width > 0.012: return StripCentury(), StripDecade() else: return StripCentury(), StripCentury()
[docs] def get_default_time_period(self): return time_period_center(self.now(), BosparanianDelta.from_days(30))
[docs] def supports_saved_now(self): return True
[docs] def set_saved_now(self, time): self.saved_now = time
[docs] def now(self): if self.saved_now is None: return BosparanianDateTime(1000, 1, 1, 12, 0, 0).to_time() return self.saved_now
[docs] def get_min_zoom_delta(self): return BosparanianDelta.from_seconds(60), _("Can't zoom deeper than 1 minute")
[docs] def get_name(self): return "bosparaniantime"
[docs] def get_duplicate_functions(self): return [ (_("Day"), move_period_num_days), (_("Week"), move_period_num_weeks), (_("Month"), move_period_num_months), (_("Year"), move_period_num_years), ]
[docs] def is_special_day(self, time): return self.get_day_of_week(time) == 3
[docs] def is_weekend_day(self, time): return self.get_day_of_week(time) in (0, 3)
[docs] @staticmethod def get_day_of_week(time): return time.julian_day % 7
[docs] @staticmethod def create_time_picker(parent, *args, **kwargs): from timelinelib.calendar.bosparanian.timepicker.datetimepicker import BosparanianDateTimePicker return BosparanianDateTimePicker(parent, *args, **kwargs)
[docs] @staticmethod def create_period_picker(parent, *args, **kwargs): from timelinelib.calendar.bosparanian.periodpicker import BosparanianPeriodPicker return BosparanianPeriodPicker(parent, *args, **kwargs)
[docs] def get_duration_types(self): return [ self.DURATION_TYPE_HOURS, self.DURATION_TYPE_WORKDAYS, self.DURATION_TYPE_DAYS, self.DURATION_TYPE_MINUTES, self.DURATION_TYPE_SECONDS]
[docs] def get_duration_divisor(self, duration_type, workday_length): return { self.DURATION_TYPE_SECONDS: 1, self.DURATION_TYPE_MINUTES: 60, self.DURATION_TYPE_HOURS: 3600, self.DURATION_TYPE_DAYS: 86400, self.DURATION_TYPE_WORKDAYS: 3600 * workday_length, }[duration_type]
[docs]def open_now_date_editor(main_frame, current_period, navigation_fn): def navigate_to(time): navigation_fn(lambda tp: tp.center(time)) open_change_now_date_dialog(main_frame, navigate_to, _("Change Now Date"))
[docs]def go_to_date_fn(main_frame, current_period, navigation_fn): def navigate_to(time): navigation_fn(lambda tp: tp.center(time)) open_time_editor_dialog(main_frame, BosparanianTimeType(), current_period.mean_time(), navigate_to, _("Go to Date"))
[docs]def backward_fn(main_frame, current_period, navigation_fn): _move_page_smart(current_period, navigation_fn, -1)
[docs]def forward_fn(main_frame, current_period, navigation_fn): _move_page_smart(current_period, navigation_fn, 1)
def _move_page_smart(current_period, navigation_fn, direction): if _whole_number_of_years(current_period): _move_page_years(current_period, navigation_fn, direction) elif _whole_number_of_months(current_period): _move_page_months(current_period, navigation_fn, direction) else: navigation_fn(lambda tp: tp.move_delta(direction * current_period.delta())) def _whole_number_of_years(period): return (BosparanianDateTime.from_time(period.start_time).is_first_day_in_year() and BosparanianDateTime.from_time(period.end_time).is_first_day_in_year() and _calculate_year_diff(period) > 0) def _move_page_years(curret_period, navigation_fn, direction): def navigate(tp): year_delta = direction * _calculate_year_diff(curret_period) bosparanian_start = BosparanianDateTime.from_time(curret_period.start_time) bosparanian_end = BosparanianDateTime.from_time(curret_period.end_time) new_start_year = bosparanian_start.year + year_delta new_end_year = bosparanian_end.year + year_delta try: new_start = bosparanian_start.replace(year=new_start_year).to_time() new_end = bosparanian_end.replace(year=new_end_year).to_time() if new_end > BosparanianTimeType().get_max_time(): raise ValueError() if new_start < BosparanianTimeType().get_min_time(): raise ValueError() except ValueError: if direction < 0: raise TimeOutOfRangeLeftError() else: raise TimeOutOfRangeRightError() return tp.update(new_start, new_end) navigation_fn(navigate) def _calculate_year_diff(period): return (BosparanianDateTime.from_time(period.end_time).year - BosparanianDateTime.from_time(period.start_time).year) def _whole_number_of_months(period): start, end = BosparanianDateTime.from_time(period.start_time), BosparanianDateTime.from_time(period.end_time) start_months = start.year * 13 + start.month end_months = end.year * 13 + end.month month_diff = end_months - start_months return (start.is_first_of_month() and end.is_first_of_month() and month_diff > 0) def _move_page_months(curret_period, navigation_fn, direction): def navigate(tp): start = BosparanianDateTime.from_time(curret_period.start_time) end = BosparanianDateTime.from_time(curret_period.end_time) start_months = start.year * 13 + start.month end_months = end.year * 13 + end.month month_diff = end_months - start_months month_delta = month_diff * direction new_start_year, new_start_month = _months_to_year_and_month(start_months + month_delta) new_end_year, new_end_month = _months_to_year_and_month(end_months + month_delta) try: new_start = start.replace(year=new_start_year, month=new_start_month) new_end = end.replace(year=new_end_year, month=new_end_month) start = new_start.to_time() end = new_end.to_time() if end > BosparanianTimeType().get_max_time(): raise ValueError() if start < BosparanianTimeType().get_min_time(): raise ValueError() except ValueError: if direction < 0: raise TimeOutOfRangeLeftError() else: raise TimeOutOfRangeRightError() return tp.update(start, end) navigation_fn(navigate) def _months_to_year_and_month(months): years = int(months // 13) month = months - years * 13 if month == 0: month = 13 years -= 1 return years, month
[docs]def forward_one_week_fn(main_frame, current_period, navigation_fn): wk = BosparanianDelta.from_days(7) navigation_fn(lambda tp: tp.move_delta(wk))
[docs]def backward_one_week_fn(main_frame, current_period, navigation_fn): wk = BosparanianDelta.from_days(7) navigation_fn(lambda tp: tp.move_delta(-1 * wk))
[docs]def forward_one_month_fn(main_frame, current_period, navigation_fn): navigate_month_step(current_period, navigation_fn, 1)
[docs]def backward_one_month_fn(main_frame, current_period, navigation_fn): navigate_month_step(current_period, navigation_fn, -1)
[docs]def forward_one_year_fn(main_frame, current_period, navigation_fn): yr = BosparanianDelta.from_days(365) navigation_fn(lambda tp: tp.move_delta(yr))
[docs]def backward_one_year_fn(main_frame, current_period, navigation_fn): yr = BosparanianDelta.from_days(365) navigation_fn(lambda tp: tp.move_delta(-1 * yr))
[docs]def fit_millennium_fn(main_frame, current_period, navigation_fn): mean = BosparanianDateTime.from_time(current_period.mean_time()) if mean.year > get_millenium_max_year(): year = get_millenium_max_year() else: year = max(get_min_year_containing_praios_1(), int(mean.year // 1000) * 1000) start = BosparanianDateTime.from_ymd(year, 1, 1).to_time() end = BosparanianDateTime.from_ymd(year + 1000, 1, 1).to_time() navigation_fn(lambda tp: tp.update(start, end))
[docs]def get_min_year_containing_praios_1(): return BosparanianDateTime.from_time(BosparanianTimeType().get_min_time()).year + 1
[docs]def get_millenium_max_year(): return BosparanianDateTime.from_time(BosparanianTimeType().get_max_time()).year - 1000
[docs]def get_century_max_year(): return BosparanianDateTime.from_time(BosparanianTimeType().get_max_time()).year - 100
[docs]def fit_century_fn(main_frame, current_period, navigation_fn): mean = BosparanianDateTime.from_time(current_period.mean_time()) if mean.year > get_century_max_year(): year = get_century_max_year() else: year = max(get_min_year_containing_praios_1(), int(mean.year // 100) * 100) start = BosparanianDateTime.from_ymd(year, 1, 1).to_time() end = BosparanianDateTime.from_ymd(year + 100, 1, 1).to_time() navigation_fn(lambda tp: tp.update(start, end))
[docs]def fit_decade_fn(main_frame, current_period, navigation_fn): mean = BosparanianDateTime.from_time(current_period.mean_time()) start = BosparanianDateTime.from_ymd(int(mean.year // 10) * 10, 1, 1).to_time() end = BosparanianDateTime.from_ymd(int(mean.year // 10) * 10 + 10, 1, 1).to_time() navigation_fn(lambda tp: tp.update(start, end))
[docs]def fit_year_fn(main_frame, current_period, navigation_fn): mean = BosparanianDateTime.from_time(current_period.mean_time()) start = BosparanianDateTime.from_ymd(mean.year, 1, 1).to_time() end = BosparanianDateTime.from_ymd(mean.year + 1, 1, 1).to_time() navigation_fn(lambda tp: tp.update(start, end))
[docs]def fit_month_fn(main_frame, current_period, navigation_fn): mean = BosparanianDateTime.from_time(current_period.mean_time()) start = BosparanianDateTime.from_ymd(mean.year, mean.month, 1).to_time() if mean.month == 13: end = BosparanianDateTime.from_ymd(mean.year + 1, 1, 1).to_time() else: end = BosparanianDateTime.from_ymd(mean.year, mean.month + 1, 1).to_time() navigation_fn(lambda tp: tp.update(start, end))
[docs]def fit_day_fn(main_frame, current_period, navigation_fn): mean = BosparanianDateTime.from_time(current_period.mean_time()) start = BosparanianDateTime.from_ymd(mean.year, mean.month, mean.day).to_time() end = start + BosparanianDelta.from_days(1) navigation_fn(lambda tp: tp.update(start, end))
[docs]def fit_week_fn(main_frame, current_period, navigation_fn): mean = BosparanianDateTime.from_time(current_period.mean_time()) start = BosparanianDateTime.from_ymd(mean.year, mean.month, mean.day).to_time() weekday = BosparanianTimeType().get_day_of_week(start) start = start - BosparanianDelta.from_days(weekday) if not main_frame.config.week_starts_on_monday(): start = start - BosparanianDelta.from_days(1) end = start + BosparanianDelta.from_days(7) navigation_fn(lambda tp: tp.update(start, end))
[docs]def move_period_num_days(period, num): delta = BosparanianDelta.from_days(1) * num start_time = period.start_time + delta end_time = period.end_time + delta return TimePeriod(start_time, end_time)
[docs]def move_period_num_weeks(period, num): delta = BosparanianDelta.from_days(7) * num start_time = period.start_time + delta end_time = period.end_time + delta return TimePeriod(start_time, end_time)
[docs]def move_period_num_months(period, num): try: delta = num years = int(abs(delta)) // 13 bosparanian_start = BosparanianDateTime.from_time(period.start_time) bosparanian_end = BosparanianDateTime.from_time(period.end_time) if num < 0: years = -years delta = delta - 13 * years if delta < 0: start_month = bosparanian_start.month + 13 + delta end_month = bosparanian_end.month + 13 + delta if start_month > 13: start_month -= 13 end_month -= 13 if start_month > bosparanian_start.month: years -= 1 else: start_month = bosparanian_start.month + delta end_month = bosparanian_start.month + delta if start_month > 13: start_month -= 13 end_month -= 13 years += 1 start_year = bosparanian_start.year + years end_year = bosparanian_start.year + years start_time = bosparanian_start.replace(year=start_year, month=start_month) end_time = bosparanian_end.replace(year=end_year, month=end_month) return TimePeriod(start_time.to_time(), end_time.to_time()) except ValueError: return None
[docs]def move_period_num_years(period, num): try: delta = num start_year = BosparanianDateTime.from_time(period.start_time).year end_year = BosparanianDateTime.from_time(period.end_time).year start_time = BosparanianDateTime.from_time(period.start_time).replace(year=start_year + delta) end_time = BosparanianDateTime.from_time(period.end_time).replace(year=end_year + delta) return TimePeriod(start_time.to_time(), end_time.to_time()) except ValueError: return None
[docs]def has_nonzero_time(time_period): return (time_period.start_time.seconds != 0 or time_period.end_time.seconds != 0)