Gnumed.timelinelib.time.wxtime

Package Gnumed :: Package timelinelib :: Package time :: Module wxtime |
[frames] | no frames]

# Source Code for Module Gnumed.timelinelib.time.wxtime

      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  import sys
     20  import re
     21
     22  import wx
     23
     24  from timelinelib.calendar.monthnames import abbreviated_name_of_month
     25  from timelinelib.db.objects import TimePeriod
     26  from timelinelib.db.objects import time_period_center
     27  from timelinelib.drawing.interface import Strip
     28  from timelinelib.drawing.utils import get_default_font
     29  from timelinelib.time.typeinterface import TimeType
     30
     31
     32  # To save computation power (used by `delta_to_microseconds`)
     33  US_PER_SEC = 1000000
     34  US_PER_HOUR = 60 * 60 * 1000 * 1000
     35  US_PER_MINUTE = 60 * 1000 * 1000
     36  US_PER_DAY = 24 * 60 * 60 * US_PER_SEC
     37  MIN_YEAR = -4700
     38  MAX_YEAR = 120000
     39
     40 -class WxTimeType(TimeType):
     41
     42 -    def __eq__(self, other):
     43          return isinstance(other, WxTimeType)
     44
     45 -    def __ne__(self, other):
     46          return not (self == other)
     47
     48 -    def time_string(self, time):
     49          return time.Format("%Y-%m-%d %H:%M:%S")
     50
     51 -    def parse_time(self, time_string):
     52          match = re.search(r"^(-?\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$", time_string)
     53          if match:
     54              year = int(match.group(1))
     55              month = int(match.group(2)) - 1
     56              day = int(match.group(3))
     57              hour = int(match.group(4))
     58              minute = int(match.group(5))
     59              second = int(match.group(6))
     60              return try_to_create_wx_date_time_from_dmy(day, month, year, hour, minute, second)
     61          else:
     62              raise ValueError("Time not on correct format = '%s'" % time_string)
     63
     86
     87 -    def is_date_time_type(self):
     88          return True
     89
     90 -    def format_period(self, time_period):
     91          """Returns a unicode string describing the time period."""
     92          def label_with_time(time):
     93              return u"%s %s" % (label_without_time(time), time_label(time))
     94          def label_without_time(time):
     95              return "%s %s %s" % (
     96                  time.Format("%d"),
     97                  abbreviated_name_of_month(int(time.Format("%m"))),
     98                  time.Format("%Y"))
     99          def time_label(time):
    100              return time.Format("%H:%M")
    101          if time_period.is_period():
    102              if time_period.has_nonzero_time():
    103                  label = u"%s to %s" % (label_with_time(time_period.start_time),
    104                                        label_with_time(time_period.end_time))
    105              else:
    106                  label = u"%s to %s" % (label_without_time(time_period.start_time),
    107                                        label_without_time(time_period.end_time))
    108          else:
    109              if time_period.has_nonzero_time():
    110                  label = u"%s" % label_with_time(time_period.start_time)
    111              else:
    112                  label = u"%s" % label_without_time(time_period.start_time)
    113          return label
    114
    115 -    def format_delta(self, delta):
    116          days = delta.days
    117          hours = delta.hours - days * 24
    118          minutes = delta.minutes - (days * 24 + hours) * 60
    119          collector = []
    120          if days == 1:
    121              collector.append(u"1 %s" % _("day"))
    122          elif days > 1:
    123              collector.append(u"%d %s" % (days, _("days")))
    124          if hours == 1:
    125              collector.append(u"1 %s" % _("hour"))
    126          elif hours > 1:
    127              collector.append(u"%d %s" % (hours, _("hours")))
    128          if minutes == 1:
    129              collector.append(u"1 %s" % _("minute"))
    130          elif minutes > 1:
    131              collector.append(u"%d %s" % (minutes, _("minutes")))
    132          delta_string = u" ".join(collector)
    133          if delta_string == "":
    134              delta_string = "0"
    135          return delta_string
    136
    137 -    def get_min_time(self):
    138          min_time = wx.DateTimeFromDMY(1, 0, MIN_YEAR)
    139          return (min_time, _("can't be before year %d") % (MIN_YEAR))
    140
    141 -    def get_max_time(self):
    142          max_time = wx.DateTimeFromDMY(1, 0, MAX_YEAR)
    143          return (max_time, _("can't be after year %d") % (MAX_YEAR))
    144
    145 -    def choose_strip(self, metrics, config):
    146          """
    147          Return a tuple (major_strip, minor_strip) for current time period and
    148          window size.
    149          """
    150          today = metrics.time_period.start_time
    151          tomorrow = today + wx.DateSpan.Day()
    152          day_period = TimePeriod(self, today, tomorrow)
    153          one_day_width = metrics.calc_exact_width(day_period)
    154          if one_day_width > 600:
    155              return (StripDay(), StripHour())
    156          elif one_day_width > 45:
    157              return (StripWeek(config), StripWeekday())
    158          elif one_day_width > 25:
    159              return (StripMonth(), StripDay())
    160          elif one_day_width > 1.5:
    161              return (StripYear(), StripMonth())
    162          elif one_day_width > 0.12:
    163              return (StripDecade(), StripYear())
    164          elif one_day_width > 0.012:
    165              return (StripCentury(), StripDecade())
    166          else:
    167              return (StripCentury(), StripCentury())
    168
    169 -    def mult_timedelta(self, delta, num):
    170          """Return a new timedelta that is `num` times larger than `delta`."""
    171          microsecs = delta_to_microseconds(delta) * num
    172          delta = microseconds_to_delta(microsecs)
    173          return delta
    174
    175 -    def get_default_time_period(self):
    176          return time_period_center(self, wx.DateTime.Now(), wx.TimeSpan.Days(30))
    177
    178 -    def now(self):
    179          return wx.DateTime.Now()
    180
    181 -    def get_time_at_x(self, time_period, x_percent_of_width):
    182          """Return the time at pixel `x`."""
    183          microsecs = delta_to_microseconds(time_period.delta())
    184          microsecs = microsecs * x_percent_of_width
    185          return time_period.start_time + microseconds_to_delta(microsecs)
    186
    187 -    def div_timedeltas(self, delta1, delta2):
    188          """Return how many times delta2 fit in delta1."""
    189          # Since Python can handle infinitely large numbers, this solution works. It
    190          # might however not be optimal. If you are clever, you should be able to
    191          # treat the different parts individually. But this is simple.
    192          total_us1 = delta_to_microseconds(delta1)
    193          total_us2 = delta_to_microseconds(delta2)
    194          # Make sure that the result is a floating point number
    195          return float(total_us1) / float(total_us2)
    196
    197 -    def get_max_zoom_delta(self):
    198          max_zoom_delta = wx.TimeSpan.Days(1200 * 365)
    199          return (max_zoom_delta, _("Can't zoom wider than 1200 years"))
    200
    201 -    def get_min_zoom_delta(self):
    202          return (wx.TimeSpan.Hour(), _("Can't zoom deeper than 1 hour"))
    203
    204 -    def get_zero_delta(self):
    205          return wx.TimeSpan()
    206
    207 -    def time_period_has_nonzero_time(self, time_period):
    208          nonzero_time = (not time_period.start_time.IsSameTime(wx.DateTimeFromHMS(0, 0, 0))  or
    209                          not time_period.end_time.IsSameTime(wx.DateTimeFromHMS(0, 0, 0))    )
    210          return nonzero_time
    211
    212 -    def get_name(self):
    213          return u"wxtime"
    214
    215 -    def get_duplicate_functions(self):
    216          return [
    217              (_("Day"), move_period_num_days),
    218              (_("Week"), move_period_num_weeks),
    219              (_("Month"), move_period_num_months),
    220              (_("Year"), move_period_num_years),
    221          ]
    222
    223 -    def zoom_is_ok(self, delta):
    224          return (delta.GetMilliseconds() > 3600000) or (delta.GetDays() > 0)
    225
    226 -    def half_delta(self, delta):
    227          microseconds = delta_to_microseconds(delta) / 2
    228          return microseconds_to_delta(microseconds)
    229
    230 -    def margin_delta(self, delta):
    231          microseconds = delta_to_microseconds(delta) / 24
    232          return microseconds_to_delta(microseconds)
    233
    234 -    def event_date_string(self, time):
    235          return time.Format("%Y-%m-%d")
    236
    237 -    def event_time_string(self, time):
    238          return time.Format("%H:%M")
    239
    240 -    def eventtimes_equals(self, time1, time2):
    241          s1 = "%s %s" % (self.event_date_string(time1),
    242                          self.event_date_string(time1))
    243          s2 = "%s %s" % (self.event_date_string(time2),
    244                          self.event_date_string(time2))
    245          return s1 == s2
    246
    247 -    def adjust_for_bc_years(self, time):
    248          if time.Year == 0:
    249              return time  + wx.DateSpan.Year()
    250          else:
    251              return time
    252
    253
    254 -def go_to_today_fn(main_frame, current_period, navigation_fn):
    255      navigation_fn(lambda tp: tp.center(wx.DateTime.Now()))
    256
    257
    258 -def go_to_date_fn(main_frame, current_period, navigation_fn):
    259      def navigate_to(time):
    260          navigation_fn(lambda tp: tp.center(time))
    261      main_frame.display_time_editor_dialog(
    262          WxTimeType(), current_period.mean_time(), navigate_to, _("Go to Date"))
    263
    264
    265 -def backward_fn(main_frame, current_period, navigation_fn):
    266      move_page_smart(current_period, navigation_fn, -1)
    267
    268
    269 -def forward_fn(main_frame, current_period, navigation_fn):
    270      move_page_smart(current_period, navigation_fn, 1)
    271
    272
    273 -def move_page_smart(current_period, navigation_fn, direction):
    274      start, end = current_period.start_time, current_period.end_time
    275      year_diff = end.Year - start.Year
    276      start_months = start.Year * 12 + start.Month
    277      end_months = end.Year * 12 + end.Month
    278      month_diff = end_months - start_months
    279      whole_years = start.Month == end.Month and start.Day == end.Day
    280      whole_months = start.Day == 1 and end.Day == 1
    281      direction_backward = direction < 0
    282      # Whole years
    283      if whole_years and year_diff > 0:
    284          _move_smart_year(navigation_fn, direction, start, end)
    285      # Whole months
    286      elif whole_months and month_diff > 0:
    287          _move_smart_month(navigation_fn, direction_backward, start, end)
    288      # No need for smart delta
    289      else:
    290          navigation_fn(lambda tp: tp.move_delta(direction*current_period.delta()))
    291
    292
    293 -def _move_smart_year(navigation_fn, direction, start, end):
    294      year_diff = direction * (end.Year - start.Year)
    295      start.SetYear(start.Year + year_diff)
    296      end.SetYear(end.Year + year_diff)
    297      navigation_fn(lambda tp: tp.update(start, end))
    298
    299
    300 -def _months_to_year_and_month(months):
    301      years = int(months / 12)
    302      month = months - years * 12
    303      if month == 12:
    304          month = 0
    305          years -=1
    306      return years, month
    307
    308
    309 -def _move_smart_month(navigation_fn, direction_backward, start, end):
    310      if direction_backward:
    311          _move_smart_month_backward(navigation_fn, start, end)
    312      else:
    313          _move_smart_month_forward(navigation_fn, start, end)
    314
    315
    316 -def _move_smart_month_backward(navigation_fn, start, end):
    317      start_months = start.Year * 12 + start.Month
    318      end_months = end.Year * 12 + end.Month
    319      month_diff = end_months - start_months
    320      new_end = start
    321      new_start_year, new_start_month = _months_to_year_and_month(
    322                                              start_months -
    323                                              month_diff)
    324      new_start = wx.DateTimeFromDMY(start.Day, new_start_month, new_start_year,
    325                                     start.Hour, start.Minute, start.Second)
    326      navigation_fn(lambda tp: tp.update(new_start, new_end))
    327
    328
    329 -def _move_smart_month_forward(navigation_fn, start, end):
    330      start_months = start.Year * 12 + start.Month
    331      end_months = end.Year * 12 + end.Month
    332      month_diff = end_months - start_months
    333      new_start = end
    334      new_end_year, new_end_month = _months_to_year_and_month(
    335                                              end_months +
    336                                              month_diff)
    337      new_end = wx.DateTimeFromDMY(end.Day, new_end_month, new_end_year,
    338                                   end.Hour, end.Minute, end.Second)
    339      navigation_fn(lambda tp: tp.update(new_start, new_end))
    340
    341
    342 -def forward_one_week_fn(main_frame, current_period, navigation_fn):
    343      week = wx.DateSpan.Week()
    344      navigation_fn(lambda tp: tp.move_delta(week))
    345
    346
    347 -def backward_one_week_fn(main_frame, current_period, navigation_fn):
    348      week = wx.DateSpan.Week()
    349      navigation_fn(lambda tp: tp.move_delta(-1 * week))
    350
    351
    352 -def navigate_month_step(current_period, navigation_fn, direction):
    353      """
    354      Currently does not notice leap years.
    355      """
    356      tm = current_period.mean_time()
    357      if direction > 0:
    358          if tm.Month == 1:
    359              d = 28
    360          elif tm.Month in (3,5,8,10):
    361              d = 30
    362          else:
    363              d = 31
    364      else:
    365          if tm.Month == 2:
    366              d = 28
    367          elif tm.Month in (4,6,9,11):
    368              d = 30
    369          else:
    370              d = 31
    371      mv = wx.DateSpan.Days(d)
    372      navigation_fn(lambda tp: tp.move_delta(direction*mv))
    373
    374
    375 -def forward_one_month_fn(main_frame, current_period, navigation_fn):
    376      navigate_month_step(current_period, navigation_fn, 1)
    377
    378
    379 -def backward_one_month_fn(main_frame, current_period, navigation_fn):
    380      navigate_month_step(current_period, navigation_fn, -1)
    381
    382
    383 -def forward_one_year_fn(main_frame, current_period, navigation_fn):
    384      yr = wx.DateSpan.Year()
    385      navigation_fn(lambda tp: tp.move_delta(yr))
    386
    387
    388 -def backward_one_year_fn(main_frame, current_period, navigation_fn):
    389      yr = wx.DateSpan.Year()
    390      navigation_fn(lambda tp: tp.move_delta(-1*yr))
    391
    392
    393 -def fit_millennium_fn(main_frame, current_period, navigation_fn):
    394      mean = current_period.mean_time()
    395      start = wx.DateTimeFromDMY(1, 0, int(mean.Year/1000)*1000)
    396      end = wx.DateTimeFromDMY(1, 0, int(mean.Year/1000)*1000 + 1000)
    397      navigation_fn(lambda tp: tp.update(start, end))
    398
    399
    400 -def fit_century_fn(main_frame, current_period, navigation_fn):
    401      mean = current_period.mean_time()
    402      start = wx.DateTimeFromDMY(1, 0, int(mean.Year/100)*100)
    403      end = wx.DateTimeFromDMY(1, 0, int(mean.Year/100)*100 + 100)
    404      navigation_fn(lambda tp: tp.update(start, end))
    405
    406
    407 -def fit_decade_fn(main_frame, current_period, navigation_fn):
    408      mean = current_period.mean_time()
    409      start = wx.DateTimeFromDMY(1, 0, int(mean.Year/10)*10)
    410      end = wx.DateTimeFromDMY(1, 0, int(mean.Year/10)*10+10)
    411      navigation_fn(lambda tp: tp.update(start, end))
    412
    413
    414 -def fit_year_fn(main_frame, current_period, navigation_fn):
    415      mean = current_period.mean_time()
    416      start = wx.DateTimeFromDMY(1, 0, mean.Year)
    417      end = wx.DateTimeFromDMY(1, 0, mean.Year + 1)
    418      navigation_fn(lambda tp: tp.update(start, end))
    419
    420
    421 -def fit_month_fn(main_frame, current_period, navigation_fn):
    422      mean = current_period.mean_time()
    423      start = wx.DateTimeFromDMY(1, mean.Month, mean.Year)
    424      if mean.Month == 11:
    425          end = wx.DateTimeFromDMY(1, 0, mean.Year + 1)
    426      else:
    427          end = wx.DateTimeFromDMY(1, mean.Month + 1, mean.Year)
    428      navigation_fn(lambda tp: tp.update(start, end))
    429
    430
    431 -def fit_day_fn(main_frame, current_period, navigation_fn):
    432      mean = current_period.mean_time()
    433      start = wx.DateTimeFromDMY(mean.Day, mean.Month, mean.Year)
    434      end = start + wx.DateSpan.Day()
    435      navigation_fn(lambda tp: tp.update(start, end))
    436
    437
    438 -def fit_week_fn(main_frame, current_period, navigation_fn):
    439      mean = current_period.mean_time()
    440      start = wx.DateTimeFromDMY(mean.Day, mean.Month, mean.Year)
    441      start.SetToWeekDayInSameWeek(1)
    442      if not main_frame.week_starts_on_monday():
    443          start = start - wx.DateSpan.Day()
    444      end = start + wx.DateSpan.Days(7)
    445      navigation_fn(lambda tp: tp.update(start, end))
    446
    447
    448 -class StripCentury(Strip):
    449
    450 -    def label(self, time, major=False):
    451          if major:
    452              # TODO: This only works for English. Possible to localize?
    453              start_year = self._century_start_year(time.Year)
    454              next_start_year = start_year + 100
    455              return str(next_start_year / 100) + " century"
    456          return ""
    457
    458 -    def start(self, time):
    459          return wx.DateTimeFromDMY(1, 0, max(self._century_start_year(time.Year), MIN_YEAR))
    460
    461 -    def increment(self, time):
    462          return time + wx.DateSpan.Years(100)
    463
    464 -    def get_font(self, time_period):
    465          return get_default_font(8)
    466
    467 -    def _century_start_year(self, year):
    468          return (int(year) / 100) * 100
    469
    470
    471 -class StripDecade(Strip):
    472
    473 -    def label(self, time, major=False):
    474          # TODO: This only works for English. Possible to localize?
    475          return str(self._decade_start_year(time.Year)) + "s"
    476
    477 -    def start(self, time):
    478          return wx.DateTimeFromDMY(1, 0, self._decade_start_year(time.Year))
    479
    480 -    def increment(self, time):
    481          return time + wx.DateSpan.Year() * 10
    482
    483 -    def _decade_start_year(self, year):
    484          return (int(year) / 10) * 10
    485
    486 -    def get_font(self, time_period):
    487          return get_default_font(8)
    488
    489
    490 -class StripYear(Strip):
    491
    492 -    def label(self, time, major=False):
    493          return str(wx.DateTime.ConvertYearToBC(time.Year))
    494
    495 -    def start(self, time):
    496          return wx.DateTimeFromDMY(1, 0, time.Year)
    497
    498 -    def increment(self, time):
    499          return time + wx.DateSpan.Year()
    500
    501 -    def get_font(self, time_period):
    502          return get_default_font(8)
    503
    504
    505 -class StripMonth(Strip):
    506
    507 -    def label(self, time, major=False):
    508          if major:
    509              return "%s %s" % (time.GetMonthName(time.Month, time.Name_Abbr), time.Year)
    510          return time.GetMonthName(time.Month, wx.DateTime.Name_Abbr)
    511
    512 -    def start(self, time):
    513          return wx.DateTimeFromDMY(1, time.Month, time.Year)
    514
    515 -    def increment(self, time):
    516          if time.Month < 11:
    517              return wx.DateTimeFromDMY(1, time.Month + 1, time.Year, 0, 0)
    518          else:
    519              return wx.DateTimeFromDMY(1, 0, time.Year + 1, 0, 0)
    520
    521 -    def get_font(self, time_period):
    522          return get_default_font(8)
    523
    524
    525 -class StripDay(Strip):
    526
    527 -    def label(self, time, major=False):
    528          if major:
    529              month_name = time.GetMonthName(time.Month, time.Name_Abbr)
    530              return "%s %s %s" % (time.Day, month_name, time.Year)
    531          return str(time.Day)
    532
    533 -    def start(self, time):
    534          return wx.DateTimeFromDMY(time.Day, time.Month, time.Year)
    535
    536 -    def increment(self, time):
    537          return time + wx.DateSpan.Day()
    538
    539 -    def get_font(self, time_period):
    540          saturday_or_sunday = (0,6)
    541          bold = False
    542          if (time_period.start_time.GetWeekDay() in saturday_or_sunday):
    543              bold = True
    544          return get_default_font(8, bold)
    545
    546
    547 -class StripWeek(Strip):
    548
    549 -    def __init__(self, config):
    550          Strip.__init__(self)
    551          self.config = config
    552
    553 -    def label(self, time, major=False):
    554          if major:
    555              # Example: Week 23 (1-7 Jan 2009)
    556              first_weekday = self.start(time)
    557              next_first_weekday = self.increment(first_weekday)
    558              last_weekday = next_first_weekday - wx.DateSpan.Day()
    559              range_string = self._time_range_string(first_weekday, last_weekday)
    560              if self.config.week_start == "monday":
    561                  return (_("Week") + " %s (%s)") % (time.GetWeekOfYear(), range_string)
    562              else:
    563                  # It is sunday (don't know what to do about week numbers here)
    564                  return range_string
    565          # This strip should never be used as minor
    566          return ""
    567
    568 -    def start(self, time):
    569          stripped_date = wx.DateTimeFromDMY(time.Day, time.Month, time.Year)
    570          if self.config.week_start == "monday":
    571              days_to_subtract = stripped_date.GetWeekDay() - 1
    572          else: # It is sunday
    573              days_to_subtract = stripped_date.GetWeekDay() % 7
    574          return stripped_date - wx.DateSpan.Days(days_to_subtract)
    575
    576 -    def increment(self, time):
    577          return time + wx.DateSpan.Week()
    578
    579 -    def get_font(self, time_period):
    580          return get_default_font(8)
    581
    582 -    def _time_range_string(self, time1, time2):
    583          """
    584          Examples:
    585
    586          * 1-7 Jun 2009
    587          * 28 Jun-3 Jul 2009
    588          * 28 Jun 08-3 Jul 2009
    589          """
    590          if time1.Year == time2.Year:
    591              if time1.Month == time2.Month:
    592                  return "%s-%s %s %s" % (time1.Day, time2.Day,
    593                                          time1.GetMonthName(time1.Month, time1.Name_Abbr),
    594                                          time1.Year)
    595              return "%s %s-%s %s %s" % (time1.Day,
    596                                         time1.GetMonthName(time1.Month, time1.Name_Abbr),
    597                                         time2.Day,
    598                                         time2.GetMonthName(time2.Month, time2.Name_Abbr),
    599                                         time1.Year)
    600          return "%s %s %s-%s %s %s" % (time1.Day,
    601                                        time1.GetMonthName(time1.Month, time1.Name_Abbr),
    602                                        time1.Year,
    603                                        time2.Day,
    604                                        time2.GetMonthName(time2.Month, time2.Name_Abbr),
    605                                        time2.Year)
    606
    607
    608 -class StripWeekday(Strip):
    609
    610 -    def label(self, time, major=False):
    611          if major:
    612              # This strip should never be used as major
    613              return ""
    614          return time.GetWeekDayName(time.GetWeekDay(), wx.DateTime.Name_Abbr)
    615
    616 -    def start(self, time):
    617          return wx.DateTimeFromDMY(time.Day, time.Month, time.Year)
    618
    619 -    def increment(self, time):
    620          return time + wx.DateSpan.Day()
    621
    622 -    def get_font(self, time_period):
    623          return get_default_font(8)
    624
    625
    626 -class StripHour(Strip):
    627
    628 -    def label(self, time, major=False):
    629          if major:
    630              # This strip should never be used as major
    631              return ""
    632          return str(time.Hour)
    633
    634 -    def start(self, time):
    635          start_time = wx.DateTimeFromDMY(time.Day, time.Month, time.Year, time.Hour)
    636          return start_time
    637
    638 -    def increment(self, time):
    639          new_time = time + wx.TimeSpan.Hour()
    640          return new_time
    641
    642 -    def get_font(self, time_period):
    643          return get_default_font(8)
    644
    645
    646 -def microseconds_to_delta(microsecs):
    647      # The wx.TimeSpan.Milliseconds(ms) take a wxLong argument instead
    648      # of the expected wxLonLong. And that's why we can't code like
    649      #     ms = delta.GetMilliseconds() / 2
    650      #     return wx.TimeSpan.Milliseconds(ms)
    651      counter = 0
    652      milliseconds = microsecs / 1000
    653      while abs(milliseconds) > sys.maxint:
    654          milliseconds = milliseconds / 2
    655          counter += 1
    656      delta = wx.TimeSpan.Milliseconds(milliseconds)
    657      while counter > 0:
    658          delta = delta * 2;
    659          counter -= 1
    660      return delta
    661
    662
    663 -def delta_to_microseconds(delta):
    664      """Return the number of microseconds that the delta represents."""
    665      days = delta.GetDays()
    666      hours = delta.GetHours()
    667      minutes = delta.GetMinutes()
    668      seconds = delta.GetSeconds()
    669      milliseconds = delta.GetMilliseconds()
    670      neg = False
    671      if days < 0:
    672          neg = True
    673          days  = -days
    674          hours = -hours
    675          minutes = -minutes
    676          seconds = -seconds
    677          milliseconds = - milliseconds
    678      microsecs = days * US_PER_DAY
    679      if hours >= 0:
    680          microsecs = hours * US_PER_HOUR
    681          if minutes >= 0:
    682              microsecs = minutes * US_PER_MINUTE
    683              if seconds >= 0:
    684                  microsecs = seconds * US_PER_SEC
    685                  if milliseconds >= 0:
    686                      microsecs = milliseconds * 1000
    687      if neg:
    688          microsecs = -microsecs
    689      return microsecs
    690
    691
    692 -def move_period_num_days(period, num):
    693      return _move_period_time_span(period, wx.TimeSpan.Days(num))
    694
    695
    696 -def move_period_num_weeks(period, num):
    697      return _move_period_time_span(period, wx.TimeSpan.Days(7*num))
    698
    699
    700 -def move_period_num_months(period, num):
    701      new_start_time = period.start_time + wx.DateSpan.Months(num)
    702      if new_start_time.Day != period.start_time.Day:
    703          return None
    704      return _move_period_time_span(period, new_start_time-period.start_time)
    705
    706
    707 -def move_period_num_years(period, num):
    708      new_start_time = period.start_time + wx.DateSpan.Years(num)
    709      if (new_start_time.Month != period.start_time.Month or
    710          new_start_time.Day != period.start_time.Day):
    711          return None
    712      return _move_period_time_span(period, new_start_time-period.start_time)
    713
    714
    715 -def _move_period_time_span(period, time_span):
    716      try:
    717          new_start = period.start_time + time_span
    718          new_end = period.end_time + time_span
    719          return TimePeriod(period.time_type, new_start, new_end)
    720      except ValueError:
    721          return None
    722
    723
    724 -def try_to_create_wx_date_time_from_dmy(day, month, year, hour=0, minute=0, second=0):
    725      def fail_with_invalid_date():
    726          raise ValueError("Invalid date")
    727      try:
    728          datetime = wx.DateTimeFromDMY(day, month, year, hour, minute, second)
    729      except AssertionError:
    730          fail_with_invalid_date()
    731      else:
    732          if not datetime.IsValid():
    733              fail_with_invalid_date()
    734          return datetime
    735