diff --git a/ChangeLog b/ChangeLog index d1fef5575..075a34ddf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2004-09-16 Don Allingham + * src/Calendar.py: removed + * src/Gregorian.py: removed + * src/Hebrew.py: removed + * src/Julian.py: removed + * src/calendars/Islamic.py: removed + * src/calendars/Persian.py: removed + * src/calendars/Makefile.am: removed + * src/Date.py: New, simpler date structure + * src/DateHandler.py: Start of a class to abstract and select + parser and display functions based off locale + * src/DateParser.py: base date parsing class (US English) + * src/DateDisplay.py: base date display class (US English) + * src/DateEdit.py: handle new date method + * src/EditPerson.py: handle new date method + * src/EventEdit.py: handle new date method + * src/GrampsCfg.py: removed redundant options due to new date class + * src/StartupDialog.py: removed redundant options due to new date class + * src/Makefile.am: handle file changes + * src/Sort.py: handle new date method + * src/ReadGedcom.py: handle new date method + * src/ReadXML.py: handle new date method + * src/WriteGedcom.py: handle new date method + * src/WriteXML.py: handle new date method + * src/RelLib.py: handle new date method + * src/gramps_main.py: handle new date method + * src/gramps.glade: handle new date method + 2004-09-14 Tim Waugh * src/plugins/Ancestors.py: Fixed SF bug #1009695. * src/docgen/PSDrawDoc.py (PSDrawDoc.__init__): Fixed base method diff --git a/src/CalSdn.py b/src/CalSdn.py new file mode 100644 index 000000000..764e63951 --- /dev/null +++ b/src/CalSdn.py @@ -0,0 +1,510 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000-2004 Donald N. Allingham +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# $Id$ + +import math + +_GRG_SDN_OFFSET = 32045 +_GRG_DAYS_PER_5_MONTHS = 153 +_GRG_DAYS_PER_4_YEARS = 1461 +_GRG_DAYS_PER_400_YEARS = 146097 + +_JLN_SDN_OFFSET = 32083 +_JLN_DAYS_PER_5_MONTHS = 153 +_JLN_DAYS_PER_4_YEARS = 1461 + +_HBR_HALAKIM_PER_DAY = 25920 +_HBR_HALAKIM_PER_LUNAR_CYCLE = 765433 +_HBR_HALAKIM_PER_METONIC_CYCLE = 179876755 +_HBR_SDN_OFFSET = 347997 +_HBR_NEW_MOON_OF_CREATION = 31524 +_HBR_NOON = 19440 +_HBR_AM3_11_20 = 9924 +_HBR_AM9_32_43 = 16789 + +_HBR_SUNDAY = 0 +_HBR_MONDAY = 1 +_HBR_TUESDAY = 2 +_HBR_WEDNESDAY= 3 +_HBR_FRIDAY = 5 + +_HBR_MONTHS_PER_YEAR = [ + 12, 12, 13, 12, 12, 13, 12, 13, 12, 12, + 13, 12, 12, 13, 12, 12, 13, 12, 13 + ] + +_HBR_YEAR_OFFSET = [ + 0, 12, 24, 37, 49, 61, 74, 86, 99, 111, 123, + 136, 148, 160, 173, 185, 197, 210, 222 + ] + +_FR_SDN_OFFSET = 2375474 +_FR_DAYS_PER_4_YEARS = 1461 +_FR_DAYS_PER_MONTH = 30 +_PRS_EPOCH = 1948320.5 +_ISM_EPOCH = 1948439.5 + +def _tishri1(metonic_year, molad_day, molad_halakim): + + tishri1 = molad_day + dow = tishri1 % 7 + leap_year = metonic_year in [ 2, 5, 7, 10, 13, 16, 18] + last_was_leap_year = metonic_year in [ 3, 6, 8, 11, 14, 17, 0] + + # Apply rules 2, 3 and 4. + if ((molad_halakim >= _HBR_NOON) or + ((not leap_year) and dow == _HBR_TUESDAY and + molad_halakim >= _HBR_AM3_11_20) or + (last_was_leap_year and dow == _HBR_MONDAY and molad_halakim >= _HBR_AM9_32_43)) : + tishri1 += 1 + dow += 1 + if dow == 7: + dow = 0 + + # Apply rule 1 after the others because it can cause an additional + # delay of one day + if dow == _HBR_WEDNESDAY or dow == _HBR_FRIDAY or dow == _HBR_SUNDAY: + tishri1 += 1 + + return tishri1 + +def _tishri_molad(inputDay): + + # Estimate the metonic cycle number. Note that this may be an under + # estimate because there are 6939.6896 days in a metonic cycle not + # 6940, but it will never be an over estimate. The loop below will + # correct for any error in this estimate. */ + + metonicCycle = (inputDay + 310) / 6940 + + # Calculate the time of the starting molad for this metonic cycle. */ + + (moladDay, moladHalakim) = _molad_of_metonic_cycle(metonicCycle) + + # If the above was an under estimate, increment the cycle number until + # the correct one is found. For modern dates this loop is about 98.6% + # likely to not execute, even once, because the above estimate is + # really quite close. + + while moladDay < (inputDay - 6940 + 310): + metonicCycle = metonicCycle + 1 + moladHalakim = moladHalakim + _HBR_HALAKIM_PER_METONIC_CYCLE + moladDay = moladDay + ( moladHalakim / _HBR_HALAKIM_PER_DAY) + moladHalakim = moladHalakim % _HBR_HALAKIM_PER_DAY + + # Find the molad of Tishri closest to this date. + + for metonicYear in range(0,18): + if moladDay > inputDay - 74: + break + + moladHalakim = moladHalakim + \ + (_HBR_HALAKIM_PER_LUNAR_CYCLE * _HBR_MONTHS_PER_YEAR[metonicYear]) + moladDay = moladDay + (moladHalakim / _HBR_HALAKIM_PER_DAY) + moladHalakim = moladHalakim % _HBR_HALAKIM_PER_DAY + else: + metonicYear = metonicYear + 1 + return (metonicCycle, metonicYear, moladDay, moladHalakim) + +def _molad_of_metonic_cycle(metonic_cycle): + + # Start with the time of the first molad after creation. + + r1 = _HBR_NEW_MOON_OF_CREATION + + # Calculate metonic_cycle * HALAKIM_PER_METONIC_CYCLE. The upper 32 + # bits of the result will be in r2 and the lower 16 bits will be + # in r1. + + r1 = r1 + (metonic_cycle * (_HBR_HALAKIM_PER_METONIC_CYCLE & 0xFFFF)) + r2 = r1 >> 16 + r2 = r2 + (metonic_cycle * ((_HBR_HALAKIM_PER_METONIC_CYCLE >> 16) & 0xFFFF)) + + # Calculate r2r1 / HALAKIM_PER_DAY. The remainder will be in r1, the + # upper 16 bits of the quotient will be in d2 and the lower 16 bits + # will be in d1. + + d2 = r2 / _HBR_HALAKIM_PER_DAY + r2 = r2 - (d2 * _HBR_HALAKIM_PER_DAY) + r1 = (r2 << 16) | (r1 & 0xFFFF) + d1 = r1 / _HBR_HALAKIM_PER_DAY + r1 = r1 - ( d1 * _HBR_HALAKIM_PER_DAY) + + molad_day = (d2 << 16) | d1 + molad_halakim = r1 + + return (molad_day,molad_halakim) + +def _start_of_year(year): + + metonic_cycle = (year - 1) / 19; + metonic_year = (year - 1) % 19; + (molad_day, molad_halakim) = _molad_of_metonic_cycle(metonic_cycle) + + molad_halakim = molad_halakim + (_HBR_HALAKIM_PER_LUNAR_CYCLE * _HBR_YEAR_OFFSET[metonic_year]) + molad_day = molad_day + (molad_halakim / _HBR_HALAKIM_PER_DAY) + molad_halakim = molad_halakim % _HBR_HALAKIM_PER_DAY + + pTishri1 = _tishri1(metonic_year, molad_day, molad_halakim); + + return (metonic_cycle, metonic_year, molad_day, molad_halakim, pTishri1) + +def hebrew_sdn(year, month, day): + """Converts a Jewish calendar date to an SDN number""" + + if month == 1 or month == 2: + # It is Tishri or Heshvan - don't need the year length. + (metonic_cycle,metonic_year,molad_day,molad_halakim,tishri1) = _start_of_year(year) + if month == 1: + sdn = tishri1 + day - 1 + else: + sdn = tishri1 + day + 29 + elif month == 3: + # It is Kislev - must find the year length. + + # Find the start of the year. + (metonic_cycle,metonic_year,molad_day,molad_halakim,tishri1) = _start_of_year(year) + + # Find the end of the year. + molad_halakim = molad_halakim + (_HBR_HALAKIM_PER_LUNAR_CYCLE*_HBR_MONTHS_PER_YEAR[metonic_year]) + molad_day = molad_day + (molad_halakim / _HBR_HALAKIM_PER_DAY) + molad_halakim = molad_halakim % _HBR_HALAKIM_PER_DAY + tishri1_after = _tishri1((metonic_year + 1) % 19, molad_day, molad_halakim) + + year_length = tishri1_after - tishri1 + + if year_length == 355 or year_length == 385: + sdn = tishri1 + day + 59 + else: + sdn = tishri1 + day + 58 + elif month == 4 or month == 5 or month == 6: + # It is Tevet, Shevat or Adar I - don't need the year length + + (metonic_cycle,metonic_year,molad_day,molad_halakim,tishri1_after) = _start_of_year(year+1) + + if _HBR_MONTHS_PER_YEAR[(year - 1) % 19] == 12: + length_of_adarI_andII = 29 + else: + length_of_adarI_andII = 59 + + if month == 4: + sdn = tishri1_after + day - length_of_adarI_andII - 237 + elif month == 5: + sdn = tishri1_after + day - length_of_adarI_andII - 208 + else: + sdn = tishri1_after + day - length_of_adarI_andII - 178 + else: + # It is Adar II or later - don't need the year length. + (metonic_cycle,metonic_year,molad_day,molad_halakim,tishri1_after) = _start_of_year(year+1) + + if month == 7: + sdn = tishri1_after + day - 207 + elif month == 8: + sdn = tishri1_after + day - 178 + elif month == 9: + sdn = tishri1_after + day - 148 + elif month == 10: + sdn = tishri1_after + day - 119 + elif month == 11: + sdn = tishri1_after + day - 89 + elif month == 12: + sdn = tishri1_after + day - 60 + elif month == 13: + sdn = tishri1_after + day - 30 + else: + return 0 + return sdn + _HBR_SDN_OFFSET + +def hebrew_ymd(sdn): + """Converts an SDN number to a Julian calendar date""" + + inputDay = sdn - _HBR_SDN_OFFSET + + (metonicCycle, metonicYear, day, halakim) = _tishri_molad(inputDay) + tishri1 = _tishri1(metonicYear, day, halakim); + + if inputDay >= tishri1: + # It found Tishri 1 at the start of the year + + Year = (metonicCycle * 19) + metonicYear + 1 + if inputDay < tishri1 + 59: + if inputDay < tishri1 + 30: + Month = 1 + Day = inputDay - tishri1 + 1 + else: + Month = 2 + Day = inputDay - tishri1 - 29 + return (Year, Month, Day) + + # We need the length of the year to figure this out, so find + # Tishri 1 of the next year. */ + + halakim = halakim + (_HBR_HALAKIM_PER_LUNAR_CYCLE * _HBR_MONTHS_PER_YEAR[metonicYear]) + day = day + (halakim / _HBR_HALAKIM_PER_DAY) + halakim = halakim % _HBR_HALAKIM_PER_DAY; + tishri1After = _tishri1((metonicYear + 1) % 19, day, halakim); + else: + # It found Tishri 1 at the end of the year. + + Year = metonicCycle * 19 + metonicYear + if inputDay >= tishri1 - 177: + # It is one of the last 6 months of the year. + if inputDay > tishri1 - 30: + Month = 13 + Day = inputDay - tishri1 + 30 + elif inputDay > tishri1 - 60: + Month = 12 + Day = inputDay - tishri1 + 60 + elif inputDay > tishri1 - 89: + Month = 11 + Day = inputDay - tishri1 + 89 + elif inputDay > tishri1 - 119: + Month = 10 + Day = inputDay - tishri1 + 119 + elif inputDay > tishri1 - 148: + Month = 9 + Day = inputDay - tishri1 + 148 + else: + Month = 8 + Day = inputDay - tishri1 + 178 + return (Year,Month,Day) + else: + if _HBR_MONTHS_PER_YEAR[(Year - 1) % 19] == 13: + Month = 7 + Day = inputDay - tishri1 + 207 + if Day > 0: + return (Year,Month,Day) + Month = Month - 1 + Day = Day + 30 + if Day > 0: + return (Year,Month,Day) + Month = Month - 1 + Day = Day + 30 + else: + Month = 6 + Day = inputDay - tishri1 + 207 + if Day > 0: + return (Year,Month,Day) + Month = Month - 1 + Day = Day + 30 + + if Day > 0: + return (Year,Month,Day) + Month = Month - 1 + Day = Day + 29 + if Day > 0: + return (Year,Month,Day) + + # We need the length of the year to figure this out, so find + # Tishri 1 of this year + tishri1After = tishri1; + (metonicCycle,metonicYear,day,halakim) = _tishri_molad(day-365) + tishri1 = _tishri1(metonicYear, day, halakim) + + yearLength = tishri1After - tishri1; + cday = inputDay - tishri1 - 29; + if yearLength == 355 or yearLength == 385 : + # Heshvan has 30 days + if day <= 30: + Month = 2 + Day = cday + return (Year,Month,Day) + day = day - 30 + else: + # Heshvan has 29 days + if day <= 29: + Month = 2 + Day = cday + return (Year,Month,Day) + + cday = cday - 29 + + # It has to be Kislev + return (Year,3,cday) + +def julian_sdn(year,month,day): + """Converts a Julian calendar date to an SDN number""" + + if year < 0: + year += 4801 + else: + year += 4800 + + # Adjust the start of the year + if month > 2: + month -= 3 + else: + month += 9 + year -= 1 + + return (year * _JLN_DAYS_PER_4_YEARS)/4 \ + + (month * _JLN_DAYS_PER_5_MONTHS+2)/5 \ + + day - _JLN_SDN_OFFSET + +def julian_ymd(sdn): + """Converts an SDN number to a Julian date""" + temp = (sdn + _JLN_SDN_OFFSET) * 4 - 1 + + # Calculate the year and day of year (1 <= day_of_year <= 366) + year = temp / _JLN_DAYS_PER_4_YEARS + day_of_year = (temp % _JLN_DAYS_PER_4_YEARS) / 4 + 1 + + # Calculate the month and day of month + temp = day_of_year * 5 - 3; + month = temp / _JLN_DAYS_PER_5_MONTHS; + day = (temp % _JLN_DAYS_PER_5_MONTHS) / 5 + 1; + + # Convert to the normal beginning of the year + if month < 10: + month += 3 + else: + year += 1 + month -= 9 + + # Adjust to the B.C./A.D. type numbering + year -= 4800 + if year <= 0: + year -= 1 + + return (year,month,day) + +def gregorian_sdn(year,month,day): + """Converts a gregorian date to an SDN number""" + if year < 0: + year += 4801 + else: + year += 4800 + + # Adjust the start of the year + if month > 2: + month -= 3 + else: + month += 9 + year -= 1 + + return(((year / 100) * _GRG_DAYS_PER_400_YEARS) / 4 + + ((year % 100) * _GRG_DAYS_PER_4_YEARS) / 4 + + (month * _GRG_DAYS_PER_5_MONTHS + 2) / 5 + + day + - _GRG_SDN_OFFSET ) + +def gregorian_ymd(sdn): + """Converts an SDN number to a gregorial date""" + temp = (_GRG_SDN_OFFSET + sdn) * 4 - 1 + + # Calculate the century (year/100) + century = temp / _GRG_DAYS_PER_400_YEARS + + # Calculate the year and day of year (1 <= day_of_year <= 366) + temp = ((temp % _GRG_DAYS_PER_400_YEARS) / 4) * 4 + 3 + year = (century * 100) + (temp / _GRG_DAYS_PER_4_YEARS) + day_of_year = (temp % _GRG_DAYS_PER_4_YEARS) / 4 + 1 + + # Calculate the month and day of month + temp = day_of_year * 5 - 3 + month = temp / _GRG_DAYS_PER_5_MONTHS + day = (temp % _GRG_DAYS_PER_5_MONTHS) / 5 + 1 + + # Convert to the normal beginning of the year + if month < 10 : + month = month + 3 + else: + year = year + 1 + month = month - 9 + + # Adjust to the B.C./A.D. type numbering + year = year - 4800 + if year <= 0: + year = year - 1 + return (year,month,day) + +def french_sdn(year,month,day): + """Converts a French Republican Calendar date to an SDN number""" + return (year*_FR_DAYS_PER_4_YEARS)/4 + \ + (month-1)*_FR_DAYS_PER_MONTH + \ + day + _FR_SDN_OFFSET + +def french_ymd(sdn): + """Converts an SDN number to a French Republican Calendar date""" + temp = (sdn-_FR_SDN_OFFSET)*4 - 1 + year = temp/_FR_DAYS_PER_4_YEARS + day_of_year = (temp%_FR_DAYS_PER_4_YEARS)/4 + month = (day_of_year/_FR_DAYS_PER_MONTH)+1 + day = (day_of_year%_FR_DAYS_PER_MONTH)+1 + return (year,month,day) + +def persian_sdn(year, month, day): + if year >= 0: + epbase = year - 474 + else: + epbase = year - 473 + + epyear = 474 + epbase % 2820 + + if month <= 7: + v1 = (month - 1) * 31 + else: + v1 = ((month - 1) * 30) + 6 + v2 = math.floor(((epyear * 682) - 110) / 2816) + v3 = (epyear - 1) * 365 + day + v4 = math.floor(epbase / 2820) * 1029983 + + return int(math.ceil(v1 + v2 + v3 + v4 + _PRS_EPOCH - 1)) + +def persian_ymd(sdn): + sdn = math.floor(sdn) + 0.5 + + depoch = sdn - 2121446 + cycle = math.floor(depoch / 1029983) + cyear = depoch % 1029983 + if cyear == 1029982: + ycycle = 2820 + else: + aux1 = math.floor(cyear / 366) + aux2 = cyear % 366 + ycycle = math.floor(((2134*aux1)+(2816*aux2)+2815)/1028522) + aux1 + 1; + + year = ycycle + (2820 * cycle) + 474 + if year <= 0: + year = year - 1; + + yday = sdn - persian_sdn(year, 1, 1) + 1 + if yday < 186: + month = math.ceil(yday / 31) + else: + month = math.ceil((yday - 6) / 30) + day = (sdn - persian_sdn(year, month, 1)) + 1 + return (int(year), int(month), int(day)) + +def islamic_sdn(year, month, day): + v1 = math.ceil(29.5 * (month - 1)) + v2 = (year - 1) * 354 + v3 = math.floor((3 + (11 *year)) / 30) + + return int(math.ceil((day + v1 + v2 + v3 + _ISM_EPOCH) - 1)) + +def islamic_ymd(sdn): + sdn = math.floor(sdn) + 0.5 + year = int(math.floor(((30*(sdn-_ISM_EPOCH))+10646)/10631)) + month = int(min(12, math.ceil((sdn-(29+islamic_sdn(year,1,1)))/29.5) + 1)) + day = int((sdn - islamic_sdn(year,month,1)) + 1) + return (year,month,day) + diff --git a/src/Calendar.py b/src/Calendar.py deleted file mode 100644 index a9d9a2124..000000000 --- a/src/Calendar.py +++ /dev/null @@ -1,547 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001-2003 Donald N. Allingham -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -""" -Calendar conversion routines for GRAMPS. - -The original algorithms for this module came from Scott E. Lee's -C implementation. The original C source can be found at Scott's -web site at http://www.scottlee.com -""" - -__author__ = "Donald N. Allingham" -__version__ = "$Revision$" - -from gettext import gettext as _ -import re -import Errors - -#------------------------------------------------------------------------- -# -# Constants -# -#------------------------------------------------------------------------- -UNDEF = -999999 -EXACT = 0 -ABOUT = 1 -BEFORE = 2 -AFTER = 3 - -#------------------------------------------------------------------------- -# -# Regular expressions for parsing -# -#------------------------------------------------------------------------- -_modifiers = '(' + \ - _("abt\.?") + '|' + \ - _("about") + '|' + \ - _("est\.?") + '|' + \ - _("circa") + '|' + \ - _("around") + '|' + \ - _("before") + '|' + \ - _("after") + '|' + \ - _("aft\.?") + '|' + \ - _("bef\.?") + \ - '|abt|aft|after|before|bef)' -_start = "^\s*" + _modifiers + "?\s*" -fmt1 = re.compile(_start+"(\S+)(\s+\d+\s*,)?\s*([?\d]+)?\s*$", re.IGNORECASE) -fmt2 = re.compile(_start+"(\d+)\.?\s+([^\d]+)(\s+\d+)?\s*$", re.IGNORECASE) -fmt3 = re.compile(_start+r"([?\d]+)\s*[./-]\s*([?\d]+)\s*[./-]\s*([?\d]+)\s*$", - re.IGNORECASE) -fmt7 = re.compile(_start+r"([?\d]+)\s*[./-]\s*([?\d]+)\s*$", re.IGNORECASE) -fmt4 = re.compile(_start+"(\S+)\s+(\d+)\s*$", re.IGNORECASE) -fmt5 = re.compile(_start+"(\d+)\s*$", re.IGNORECASE) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -def set_format_code(code): - Calendar.FORMATCODE = code - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -def get_format_code(): - return Calendar.FORMATCODE - -#------------------------------------------------------------------------- -# -# Calendar - base calendar -# -#------------------------------------------------------------------------- -class Calendar: - - ENTRYCODE = 0 - FORMATCODE = 0 - - MONTHS = [ - _("January"), _("February"), _("March"), _("April"), - _("May"), _("June"), _("July"), _("August"), - _("September"), _("October"), _("November"), _("December")] - - M2NUM = { - (unicode(MONTHS[0])[0:3]).lower(): 1, (unicode(MONTHS[1])[0:3]).lower(): 2, - (unicode(MONTHS[2])[0:3]).lower(): 3, (unicode(MONTHS[3])[0:3]).lower(): 4, - (unicode(MONTHS[4])[0:3]).lower(): 5, (unicode(MONTHS[5])[0:3]).lower(): 6, - (unicode(MONTHS[6])[0:3]).lower(): 7, (unicode(MONTHS[7])[0:3]).lower(): 8, - (unicode(MONTHS[8])[0:3]).lower(): 9, (unicode(MONTHS[9])[0:3]).lower(): 10, - (unicode(MONTHS[10])[0:3]).lower(): 11, (unicode(MONTHS[11])[0:3]).lower(): 12 - } - - M2V = { - _("abt") : ABOUT, _("about") : ABOUT, - _("abt.") : ABOUT, _("est") : ABOUT, - _("est.") : ABOUT, _("circa") : ABOUT, - _("around") : ABOUT, _("before") : BEFORE, - _("bef") : BEFORE, _("bef.") : BEFORE, - _("after") : AFTER, _("aft.") : AFTER, - _("aft") : AFTER, - # And the untranslated versions for reading saved data from XML. - "abt" : ABOUT, "about" : ABOUT, - "bef" : BEFORE, "bef." : BEFORE, - "aft." : AFTER, "abt." : ABOUT, - "est." : ABOUT, "est" : ABOUT, - "after" : AFTER, "before" : BEFORE, - "aft" : AFTER, - } - - MODE = { - ABOUT : _("about"), - BEFORE : _("before"), - AFTER : _("after")} - - EM2NUM ={ - "jan" : 1, "feb" : 2, "mar" : 3, "apr" : 4, - "may" : 5, "jun" : 6, "jul" : 7, "aug" : 8, - "sep" : 9, "oct" :10, "nov" : 11,"dec" : 12 - } - - NAME = "Undefined Calendar" - TNAME = _("Undefined Calendar") - - def mlen(self): - return -1 - - def __init__(self,source=None): - if source: - self.get_ymd(source.get_sdn()) - - def month(self,val): - try: - return unicode(Calendar.MONTHS[val-1]) - except: - return u'Illegal Month' - - def check(self,year,month,day): - return 1 - - def quote_display(self,year,month,day,mode): - return "%04d-%02d-%02d (%s)" % (year,month,day,Calendar.NAME) - - def display(self,year,month,day,mode): - return _FMT_FUNC[Calendar.FORMATCODE](self,year,month,day,mode) - - def format_yymmdd(self,year,month,day,mode): - if month == UNDEF and day == UNDEF and year == UNDEF : - return "" - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = "????-%02d-??" % (month) - else: - retval = "%04d-%02d" % (year,month) - elif month == UNDEF: - retval = "%04d-??-%02d" % (year,day) - else: - if year == UNDEF: - retval = "????-%02d-%02d" % (month,day) - else: - retval = "%04d-%02d-%02d" % (year,month,day) - return self.fmt_mode(retval,mode) - - def format_mon_dd_year(self,year,month,day,mode): - """ - Formats the date in the form of DD Month Year, such as - January 20, 2000 - """ - if month == UNDEF and day == UNDEF and year == UNDEF: - return "" - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = self.month(month) - else: - retval = "%s %d" % (self.month(month),year) - elif month == UNDEF: - retval = str(year) - else: - if year == UNDEF: - retval = "%s %d, ????" % (self.month(month),day) - else: - retval = "%s %d, %d" % (self.month(month),day,year) - - return self.fmt_mode(retval,mode) - - - def format_MON_dd_year(self,year,month,day,mode): - """ - Formats the date in the form of DD Month Year, such as - January 20, 2000 - """ - if month == UNDEF and day == UNDEF and year == UNDEF: - return "" - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = self.month(month).upper()[0:3] - else: - retval = "%s %d" % (self.month(month).upper()[0:3],year) - elif month == UNDEF: - retval = str(year) - else: - if year == UNDEF: - retval = "%s %d, ????" % (self.month(month).upper()[0:3],day) - else: - retval = "%s %d, %d" % (self.month(month).upper()[0:3],day,year) - - return self.fmt_mode(retval,mode) - - def format_dd_mon_year(self,year,month,day,mode): - """ - Formats the date in the form of DD Month Year, such as - 20 January 2000 - """ - if year==UNDEF: - if month == UNDEF: - d = "" - elif day == UNDEF: - d = self.month(month) - else: - d = "%02d %s" % (day,self.month(month)) - elif month == UNDEF: - d = str(year) - elif day == UNDEF: - d = "%s %d" % (self.month(month),year) - else: - d = "%02d %s %d" % (day,self.month(month),year) - - return self.fmt_mode(d,mode) - - def format_dd_MON_year(self,year,month,day,mode): - """ - Formats the date in the form of DD. Month Year, such as - 20. January 2000 - """ - if month == UNDEF and day == UNDEF and year == UNDEF : - return "" - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = self.month(month).upper()[0:3] - else: - retval = "%s %d" % (self.month(month).upper()[0:3],year) - elif month == UNDEF: - retval = str(year) - else: - month_str = self.month(month).upper()[0:3] - if year == UNDEF: - retval = "%d %s ????" % (day,month_str) - else: - retval = "%d %s %d" % (day,month_str,year) - - return self.fmt_mode(retval,mode) - - def format_dd_dot_MON_year(self,year,month,day,mode): - """ - Formats the date in the form of DD. Month Year, such as - 20. January 2000 - """ - if month == UNDEF and day == UNDEF and year == UNDEF : - return "" - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = self.month(month).upper()[0:3] - else: - retval = "%s %d" % (self.month(month).upper()[0:3],year) - elif month == UNDEF: - retval = str(year) - else: - month_str = self.month(month).upper()[0:3] - if year == UNDEF: - retval = "%d. %s ????" % (day,month_str) - else: - retval = "%d. %s %d" % (day,month_str,year) - - return self.fmt_mode(retval,mode) - - def format4(self,year,month,day,mode): - return self._get_mmddyyyy(year,month,day,mode,"/") - - def format5(self,year,month,day,mode): - return self._get_mmddyyyy(year,month,day,mode,"-") - - def format6(self,year,month,day,mode): - return self._get_ddmmyyyy(year,month,day,mode,"/") - - def format7(self,year,month,day,mode): - return self._get_ddmmyyyy(year,month,day,mode,"-") - - def format8(self,year,month,day,mode): - return self._get_mmddyyyy(year,month,day,mode,".") - - def format9(self,year,month,day,mode): - return self._get_ddmmyyyy(year,month,day,mode,".") - - def format11(self,year,month,day,mode): - return self._get_yyyymmdd(year,month,day,mode,"/") - - def format12(self,year,month,day,mode): - return self._get_yyyymmdd(year,month,day,mode,"-") - - def format13(self,year,month,day,mode): - return self._get_yyyymmdd(year,month,day,mode,".") - - def _get_mmddyyyy(self,year,month,day,mode,sep): - if month == UNDEF and day == UNDEF and year == UNDEF : - return "" - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = "%02d%s??%s??" % (month,sep,sep) - else: - retval = "%02d%s??%s%04d" % (month,sep,sep,year) - elif month == UNDEF: - retval = "??%s%02d%s%04d" % (sep,day,sep,year) - else: - if year == UNDEF: - retval = "%02d%s%02d%s????" % (month,sep,day,sep) - else: - retval = "%02d%s%02d%s%04d" % (month,sep,day,sep,year) - - return self.fmt_mode(retval,mode) - - def _get_yyyymmdd(self,year,month,day,mode,sep): - retval = "" - - if month == UNDEF and day == UNDEF and year == UNDEF : - pass - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = "????%s%02d%s??" % (sep,month,sep) - else: - retval = "%04d%s%02d" % (year,sep,month) - elif month == UNDEF: - retval = "%04d%s??%s%02d" % (year,sep,sep,day) - else: - if year == UNDEF: - retval = "????%s%02d%s%02d" % (sep,month,sep,day) - else: - retval = "%02d%s%02d%s%02d" % (year,sep,month,sep,day) - - return self.fmt_mode(retval,mode) - - def _get_ddmmyyyy(self,year,month,day,mode,sep): - retval = "" - - if month == UNDEF and day == UNDEF and year == UNDEF : - pass - elif day == UNDEF: - if month == UNDEF: - retval = str(year) - elif year == UNDEF: - retval = "??%s%02d%s??" % (sep,month,sep) - else: - retval = "??%s%02d%s%04d" % (sep,month,sep,year) - elif month == UNDEF: - retval = "%02d%s??%s%04d" % (day,sep,sep,year) - else: - if year == UNDEF: - retval = "%02d%s%02d%s????" % (day,sep,month,sep) - else: - retval = "%02d%s%02d%s%04d" % (day,sep,month,sep,year) - - return self.fmt_mode(retval,mode) - - def fmt_mode(self,val,mode): - if Calendar.MODE.has_key(mode): - return "%s %s" % (Calendar.MODE[mode],val) - else: - return val - - def get_ymd(self,val): - return (0,0,0) - - def get_sdn(self,y,m,d): - return 0 - - def set_mode_value(self,val): - if not val: - return EXACT - else: - try: - return Calendar.M2V[val.lower()] - except KeyError: - return EXACT - - def set_value(self,s): - try: - return int(s) - except: - return UNDEF - - def set_month_string(self,text): - val = unicode(text)[0:3] - val = val.lower() - try: - return Calendar.M2NUM[val] - except KeyError: - if Calendar.EM2NUM.has_key(val): - return Calendar.EM2NUM[val] - else: - return UNDEF - - def set(self,text): - mode = UNDEF - year = UNDEF - month = UNDEF - day = UNDEF - - match = fmt2.match(text) - if match != None: - matches = match.groups() - mode = self.set_mode_value(matches[0]) - month = self.set_month_string(unicode(matches[2])) - if month != UNDEF: - day = self.set_value(matches[1]) - if len(matches) == 4 and matches[3] != None: - year = self.set_value(matches[3]) - return (year,month,day,mode) - - match = fmt5.match(text) - if match != None: - matches = match.groups() - mode = self.set_mode_value(matches[0]) - year = self.set_value(matches[1]) - return (year,month,day,mode) - - match = fmt7.match(text) - if match != None: - matches = match.groups() - mode = self.set_mode_value(matches[0]) - if Calendar.ENTRYCODE == 2: - month = self.set_value(matches[2]) - year = self.set_value(matches[1]) - else: - month = self.set_value(matches[1]) - year = self.set_value(matches[2]) - return (year,month,day,mode) - - match = fmt3.match(text) - if match != None: - matches = match.groups() - mode = self.set_mode_value(matches[0]) - if Calendar.ENTRYCODE == 0: - month = self.set_value(matches[1]) - day = self.set_value(matches[2]) - year = self.set_value(matches[3]) - elif Calendar.ENTRYCODE == 1: - month = self.set_value(matches[2]) - day = self.set_value(matches[1]) - year = self.set_value(matches[3]) - else: - month = self.set_value(matches[2]) - day = self.set_value(matches[3]) - year = self.set_value(matches[1]) - return (year,month,day,mode) - - match = fmt1.match(text) - if match != None: - matches = match.groups() - mode = self.set_mode_value(matches[0]) - month = self.set_month_string(unicode(matches[1])) - if month != UNDEF: - if matches[2]: - val = matches[2].replace(',','') - day = self.set_value(val) - year = self.set_value(matches[3]) - return (year,month,day,mode) - - match = fmt4.match(text) - if match != None: - matches = match.groups() - mode = self.set_mode_value(matches[0]) - month = self.set_month_string(unicode(matches[1])) - if month != UNDEF: - if len(matches) == 4: - year = self.set_value(matches[3]) - return (year,month,day,mode) - - raise Errors.DateError - - -_FMT_FUNC = [ - Calendar.format_mon_dd_year, - Calendar.format_MON_dd_year, - Calendar.format_dd_MON_year, - Calendar.format4, - Calendar.format5, - Calendar.format6, - Calendar.format7, - Calendar.format8, - Calendar.format9, - Calendar.format_dd_dot_MON_year, - Calendar.format11, - Calendar.format12, - Calendar.format13, - ] - -#------------------------------------------------------------------------- -# -# Calendar registration -# -#------------------------------------------------------------------------- - -_calendars = {} - -def register( class_obj ): - _calendars[class_obj.NAME] = class_obj - -def find_calendar(name): - try: - return _calendars[name] - except: - return None - -def calendar_names(): - dlist = _calendars.values() - dlist.sort() - return dlist diff --git a/src/Date.py b/src/Date.py index 33fde9463..440e4ccb3 100644 --- a/src/Date.py +++ b/src/Date.py @@ -25,41 +25,60 @@ __author__ = "Donald N. Allingham" __version__ = "$Revision$" -#------------------------------------------------------------------------- -# -# python modules -# -#------------------------------------------------------------------------- -from re import IGNORECASE, compile -import string -import time - -#------------------------------------------------------------------------- -# -# gramps modules -# -#------------------------------------------------------------------------- -import Calendar -import Gregorian -import Julian -import Hebrew -import FrenchRepublic -import Errors - -from gettext import gettext as _ +from CalSdn import * #------------------------------------------------------------------------- # # Constants # #------------------------------------------------------------------------- -UNDEF = -999999 -_calendar_val = [ - Gregorian.Gregorian, - Julian.Julian, - Hebrew.Hebrew, - FrenchRepublic.FrenchRepublic, +MOD_NONE = 0 +MOD_BEFORE = 1 +MOD_AFTER = 2 +MOD_ABOUT = 3 +MOD_RANGE = 4 +MOD_SPAN = 5 +MOD_TEXTONLY = 6 + +QUAL_NONE = 0 +QUAL_ESTIMATED = 1 +QUAL_CALCULATED= 2 + +CAL_GREGORIAN = 0 +CAL_JULIAN = 1 +CAL_HEBREW = 2 +CAL_FRENCH = 3 +CAL_PERSIAN = 4 +CAL_ISLAMIC = 5 + +EMPTY = (0,0,0,False) + +_POS_DAY = 0 +_POS_MON = 1 +_POS_YR = 2 +_POS_SL = 3 +_POS_RDAY = 4 +_POS_RMON = 5 +_POS_RYR = 6 +_POS_RSL = 7 + +_calendar_convert = [ + gregorian_sdn, + julian_sdn, + hebrew_sdn, + french_sdn, + persian_sdn, + islamic_sdn, + ] + +_calendar_change = [ + gregorian_ymd, + julian_ymd, + hebrew_ymd, + french_ymd, + persian_ymd, + islamic_ymd, ] #------------------------------------------------------------------------- @@ -70,408 +89,349 @@ _calendar_val = [ class Date: """ The core date handling class for GRAMPs. Supports partial dates, - date ranges, and alternate calendars. + compound dates and alternate calendars. """ - formatCode = 0 - - fstr = _("(from|between|bet|bet.)") - tstr = _("(and|to|-)") - - fmt = compile("\s*%s\s+(.+)\s+%s\s+(.+)\s*$" % (fstr,tstr),IGNORECASE) - fmt1 = compile("\s*([^-]+)\s*-\s*([^-]+)\s*$",IGNORECASE) + + calendar_names = ["Gregorian", + "Julian", + "Hebrew", + "French Republican", + "Persian", + "Islamic"] def __init__(self,source=None): + """ + Creates a new Date instance. + """ if source: - self.start = SingleDate(source.start) - if source.stop: - self.stop = SingleDate(source.stop) - else: - self.stop = None - self.range = source.range - self.text = source.text self.calendar = source.calendar + self.modifier = source.modifier + self.quality = source.quality + self.dateval = source.dateval + self.text = source.text + self.sortval = source.sortval + self.comment = source.comment else: - self.start = SingleDate() - self.stop = None - self.range = 0 - self.text = "" - self.calendar = Gregorian.Gregorian() + self.calendar = CAL_GREGORIAN + self.modifier = MOD_TEXTONLY + self.quality = QUAL_NONE + self.dateval = EMPTY + self.text = u"" + self.sortval = 0 + self.comment = u"" + def __cmp__(self,other): + """ + Comparison function. Allows the usage of equality tests. + This allows you do run statements like 'date1 <= date2' + """ + return cmp(self.sortval,other.sortval) + + def __str__(self): + """ + Produces a string representation of the Date object. If the + date is not valid, the text representation is displayed. If + the date is a range or a span, a string in the form of + 'YYYY-MM-DD - YYYY-MM-DD' is returned. Otherwise, a string in + the form of 'YYYY-MM-DD' is returned. + """ + if self.quality == QUAL_ESTIMATED: + qual = "est " + elif self.quality == QUAL_CALCULATED: + qual = "calc " + else: + qual = "" + + if self.modifier == MOD_BEFORE: + pref = "bef " + elif self.modifier == MOD_AFTER: + pref = "aft " + elif self.modifier == MOD_ABOUT: + pref = "abt " + else: + pref = "" + + if self.modifier == MOD_TEXTONLY: + val = self.text + elif self.modifier == MOD_RANGE or self.modifier == MOD_SPAN: + val = "%04d-%02d-%02d - %04d-%02d-%02d" % ( + self.dateval[_POS_YR],self.dateval[_POS_MON],self.dateval[_POS_DAY], + self.dateval[_POS_RYR],self.dateval[_POS_RMON],self.dateval[_POS_RDAY]) + else: + val = "%04d-%02d-%02d" % ( + self.dateval[_POS_YR],self.dateval[_POS_MON],self.dateval[_POS_DAY]) + return "%s%s%s" % (qual,pref,val) + + def get_sort_value(self): + """ + Returns the sort value of Date object. If the value is a + text string, 0 is returned. Otherwise, the calculated sort + date is returned. The sort date is rebuilt on every assignment. + + The sort value is an integer representing the value. A date of + March 5, 1990 would have the value of 19900305. + """ + return self.sortval + + def get_modifier(self): + """ + Returns an integer indicating the calendar selected. The valid + values are: + + MOD_NONE = no modifier (default) + MOD_BEFORE = before + MOD_AFTER = after + MOD_ABOUT = about + MOD_RANGE = date range + MOD_SPAN = date span + MOD_TEXTONLY = text only + """ + return self.modifier + + def set_comment(self,comment): + """ + Sets the comment for the date. + """ + self.comment = comment + + def get_comment(self): + """ + Returns the associated comment. + """ + return self.comment + + def set_modifier(self,val): + """ + Sets the modifier for the date. + """ + self.modifier = val + + def get_quality(self): + """ + Returns an integer indicating the calendar selected. The valid + values are: + + QUAL_NONE = normal (default) + QUAL_ESTIMATED = estimated + QUAL_CALCULATED = calculated + """ + return self.modifier + + def set_quality(self,val): + """ + Sets the quality selected for the date. + """ + self.quality = val + def get_calendar(self): + """ + Returns an integer indicating the calendar selected. The valid + values are: + + CAL_GREGORIAN - Gregorian calendar + CAL_JULIAN - Julian calendar + CAL_HEBREW - Hebrew (Jewish) calendar + CAL_FRENCH - French Republican calendar + CAL_PERSIAN - Persian calendar + CAL_ISLAMIC - Islamic calendar + """ return self.calendar def set_calendar(self,val): - self.calendar = val() - self.start.convert_to(val) - if self.stop: - self.stop.convert_to(val) - - def set_calendar_obj(self,val): + """ + Sets the calendar selected for the date. + """ self.calendar = val - self.start.convert_to_obj(val) - if self.stop: - self.stop.convert_to_obj(val) - - def set_calendar_val(self,integer): - val = _calendar_val[integer] - self.calendar = val() - self.start.convert_to(val) - if self.stop: - self.stop.convert_to(val) def get_start_date(self): - return self.start + """ + Returns a tuple representing the start date. If the date is a + compound date (range or a span), it is the first part of the + compound date. If the date is a text string, a tuple of + (0,0,0,False) is returned. Otherwise, a date of (DD,MM,YY,slash) + is returned. If slash is True, then the date is in the form of 1530/1. + """ + if self.modifier == MOD_TEXTONLY: + val = EMPTY + else: + val = self.dateval[0:4] + return val def get_stop_date(self): - if self.stop == None: - self.stop = SingleDate() - self.stop.calendar = self.calendar - return self.stop - - def get_low_year(self): - return self.start.get_year() - - def get_high_year(self): - if self.stop == None: - return self.start.get_year() + """ + Returns a tuple representing the second half of a compound date. + If the date is not a compound date, (including text strings) a tuple + of (0,0,0,False) is returned. Otherwise, a date of (DD,MM,YY,slash) + is returned. If slash is True, then the date is in the form of 1530/1. + """ + if self.modifier == MOD_RANGE or self.modifier == MOD_SPAN: + val = self.dateval[4:8] else: - return self.stop.get_year() + val = EMPTY + return val + + def _get_low_item(self,index): + if self.modifier == MOD_TEXTONLY: + val = 0 + else: + val = self.dateval[index] + return val + + def _get_low_item_valid(self,index): + if self.modifier == MOD_TEXTONLY: + val = False + else: + val = self.dateval[index] != 0 + return val + + def _get_high_item(self,index): + if self.modifier == MOD_SPAN or self.modifier == MOD_RANGE: + val = self.dateval[index] + else: + val = 0 + return val def get_year(self): - return self.start.year + """ + Returns the year associated with the date. If the year is + not defined, a zero is returned. If the date is a compound + date, the lower date year is returned. + """ + return self._get_low_item(_POS_YR) def get_year_valid(self): - return self.start.year != UNDEF + return self._get_low_item_valid(_POS_YR) def get_month(self): - if self.start.month == UNDEF: - return UNDEF - return self.start.month + """ + Returns the month associated with the date. If the month is + not defined, a zero is returned. If the date is a compound + date, the lower date month is returned. + """ + return self._get_low_item(_POS_MON) def get_month_valid(self): - return self.start.month != UNDEF + return self._get_low_item_valid(_POS_MON) def get_day(self): - return self.start.day + """ + Returns the day of the month associated with the date. If + the day is not defined, a zero is returned. If the date is + a compound date, the lower date day is returned. + """ + return self._get_low_item(_POS_DAY) def get_day_valid(self): - return self.start.day != UNDEF + return self._get_low_item_valid(_POS_DAY) def get_valid(self): """ Returns true if any part of the date is valid""" - return self.start.year != UNDEF or self.start.month != UNDEF or self.start.day != UNDEF + return self.modifier != MOD_TEXTONLY def get_incomplete(self): - return self.range == 0 and self.start.year == UNDEF or \ - self.start.month == UNDEF or self.start.day == UNDEF + pass def get_stop_year(self): - if self.stop == None: - self.stop = SingleDate() - self.stop.calendar = self.calendar - return self.stop.year + """ + Returns the day of the year associated with the second + part of a compound date. If the year is not defined, a zero + is returned. + """ + return self._get_high_item(_POS_RYR) def get_stop_month(self): - if self.stop == None: - self.stop = SingleDate() - self.stop.calendar = self.calendar - return self.stop.month+1 + """ + Returns the month of the month associated with the second + part of a compound date. If the month is not defined, a zero + is returned. + """ + return self._get_high_item(_POS_RMON) def get_stop_day(self): - if self.stop == None: - self.stop = SingleDate() - self.stop.calendar = self.calendar - return self.stop.day + """ + Returns the day of the month associated with the second + part of a compound date. If the day is not defined, a zero + is returned. + """ + return self._get_high_item(_POS_RDAY) def get_text(self): + """ + Returns the text value associated with an invalid date. + """ return self.text - def greater_than(self,other): - return compare_dates(self,other) > 0 + def set(self,quality,modifier,calendar,value): + """ + Sets the date to the specified value. Parameters are: - def less_than(self,other): - return compare_dates(self,other) < 0 + quality - The date quality for the date (see get_quality + for more information) + modified - The date modifier for the date (see get_modifier + for more information) + calendar - The calendar associated with the date (see + get_calendar for more information). + value - A tuple representing the date information. For a + non-compound date, the format is (DD,MM,YY,slash) + and for a compound date the tuple stores data as + (DD,MM,YY,slash1,DD,MM,YY,slash2) - def equal_to(self,other): - return compare_dates(self,other) == 0 + The sort value is recalculated. + """ + self.quality = quality + self.modifier = modifier + self.calendar = calendar + self.dateval = value + year = max(value[_POS_YR],1) + month = max(value[_POS_MON],1) + day = max(value[_POS_DAY],1) + self.sortval = _calendar_convert[calendar](year,month,day) - def set(self,text): - if text.strip() == "": - self.start = SingleDate() - self.stop = None - self.range = 0 - self.text = "" - self.calendar = Gregorian.Gregorian() + def convert_calendar(self,calendar): + """ + Converts the date from the current calendar to the specified + calendar. + """ + if calendar == self.calendar: return - - try: - match = Date.fmt.match(text) - if match: - matches = match.groups() - self.start.set(matches[1]) - self.range = 0 - if self.stop == None: - self.stop = SingleDate() - self.stop.calendar = self.calendar - self.stop.set(matches[3]) - self.range = 1 - return - - match = Date.fmt1.match(text) - if match: - matches = match.groups() - self.start.set(matches[0]) - self.range = 0 - if self.stop == None: - self.stop = SingleDate() - self.stop.calendar = self.calendar - self.stop.set(matches[1]) - self.range = 1 - return + (y,m,d) = _calendar_change[calendar](self.sortval) + if self.is_compound(): + ry = max(self.dateval[_POS_RYR],1) + rm = max(self.dateval[_POS_RMON],1) + rd = max(self.dateval[_POS_RDAY],1) + sdn = _calendar_convert[self.calendar](ry,rm,rd) + (ny,nm,nd) = _calendar_change[calendar](sdn) + self.dateval = (d,m,y,self.dateval[_POS_SL], + nd,nm,ny,self.dateval[_POS_RSL]) + else: + self.dateval = (d,m,y,self.dateval[_POS_SL]) + self.calendar = calendar - self.start.set(text) - self.range = 0 - except Errors.DateError: - if text != "": - self.range = -1 - self.text = text + def set_as_text(self,text): + """ + Sets the day to a text string, and assigns the sort value + to zero. + """ + self.modifier = MOD_TEXTONLY + self.text = text + self.sortval = 0 - def set_text(self,text): - self.range = -1 + def set_text_value(self,text): + """ + Sets the day to a text string, and assigns the sort value + to zero. + """ self.text = text - def set_range(self,val): - self.range = val - - def get_date(self): - if self.range == 0: - return self.start.get_date() - elif self.range == -1: - return self.text - else: - return _("from %(start_date)s to %(stop_date)s") % { - 'start_date' : self.start.get_date(), - 'stop_date' : self.stop.get_date() } - - def get_quote_date(self): - if self.range == 0: - return self.start.get_quote_date() - elif self.range == -1: - if self.text: - return '"%s"' % self.text - else: - return '' - else: - return _("from %(start_date)s to %(stop_date)s") % { - 'start_date' : self.start.get_quote_date(), - 'stop_date' : self.stop.get_quote_date() } - def is_empty(self): - s = self.start - return s.year==UNDEF and s.month==UNDEF and s.day==UNDEF and not self.text - - def is_valid(self): - if self.range == -1: - return 0 - elif self.range: - return self.start.get_valid() and self.stop.get_valid() - return self.start.get_valid() - - def is_range(self): - return self.range == 1 + """ + Returns True if the date is a date range or a date span. + """ + return self.modifier == MOD_TEXTONLY -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class SingleDate: - "Date handling" + def is_compound(self): + """ + Returns True if the date is a date range or a date span. + """ + return self.modifier == MOD_RANGE or self.modifier == MOD_SPAN - def __init__(self,source=None): - if source: - self.month = source.month - self.day = source.day - self.year = source.year - self.mode = source.mode - self.calendar = source.calendar - else: - self.month = UNDEF - self.day = UNDEF - self.year = UNDEF - self.mode = Calendar.EXACT - self.calendar = Gregorian.Gregorian() - - def set_mode(self,val): - self.mode = self.calendar.set_mode_value(val) - - def set_month(self,val): - if val > 14 or val < 0: - self.month = UNDEF - else: - self.month = val - - def set_month_val(self,s): - self.month = self.calendar.set_value(s) - - def set_day_val(self,s): - self.day = self.calendar.set_value(s) - - def set_year_val(self,s): - if s: - self.year = self.calendar.set_value(s) - else: - self.year = UNDEF - - def get_month(self): - return self.month - - def get_month_valid(self): - return self.month != UNDEF - - def set_day(self,val): - self.day = val - - def get_day(self): - return self.day - - def get_day_valid(self): - return self.day != UNDEF - - def set_year(self,val): - self.year = val - - def get_year(self): - return self.year - - def get_year_valid(self): - return self.year != UNDEF - - def get_valid(self): - """ Returns true if any part of the date is valid""" - if self.year == UNDEF and self.month == UNDEF and self.day == UNDEF: - return 1 - return self.calendar.check(self.year,self.month,self.day) - - def set_month_str(self,text): - self.calendar.set_month_string(text) - - def get_month_str(self): - return self.calendar.month(self.month) - - def get_iso_date(self): - if self.year == UNDEF: - y = "????" - else: - y = "%04d" % self.year - if self.month == UNDEF: - if self.day == UNDEF: - m = "" - else: - m = "-??" - else: - m = "-%02d" % (self.month) - if self.day == UNDEF: - d = '' - else: - d = "-%02d" % self.day - return "%s%s%s" % (y,m,d) - - - def get_date(self): - return self.calendar.display(self.year, self.month, self.day, self.mode) - - def get_quote_date(self): - if self.year == UNDEF and self.month == UNDEF and self.day == UNDEF: - return "" - else: - return self.calendar.quote_display(self.year, self.month, self.day, self.mode) - - def set_iso_date(self,v): - data = string.split(v) - if len(data) > 1: - self.set_mode(data[0]) - v = data[1] - - vals = string.split(v,'-') - self.set_year_val(vals[0]) - if len(vals) > 1: - try: - self.set_month_val(int(vals[1])) - except: - self.month = UNDEF - else: - self.month = UNDEF - if len(vals) > 2: - self.set_day_val(vals[2]) - else: - self.day = UNDEF - - def get_mode_val(self): - return self.mode - - def set_mode_val(self,val): - self.mode = val - - def set(self,text): - self.year, self.month, self.day, self.mode = self.calendar.set(text) - - def convert_to(self,val): - sdn = self.calendar.get_sdn(self.year, self.month, self.day) - self.calendar = val() - (self.year, self.month, self.day) = self.calendar.get_ymd(sdn) - - def convert_to_obj(self,val): - sdn = self.calendar.get_sdn(self.year, self.month, self.day) - self.calendar = val - (self.year, self.month, self.day) = self.calendar.get_ymd(sdn) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -def not_too_old(date): - time_struct = time.localtime(time.time()) - current_year = time_struct[0] - if date.year != UNDEF and current_year - date.year > 110: - return 0 - return 1 - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -def compare_dates(f,s): - if f.calendar.NAME != s.calendar.NAME: - return 1 - if f.range == -1 and s.range == -1: - return cmp(f.text,s.text) - if f.range == -1 or s.range == -1: - return -1 - if f.range != s.range: - return 1 - - first = f.get_start_date() - second = s.get_start_date() - if first.mode != second.mode: - return 1 - elif first.year != second.year: - return cmp(first.year,second.year) - elif first.month != second.month: - return cmp(first.month,second.month) - elif first.day != second.day: - return cmp(first.day,second.day) - elif f.range == 1: - first = f.get_stop_date() - second = s.get_stop_date() - if first.mode != second.mode: - return 1 - elif first.year != second.year: - return cmp(first.year,second.year) - elif first.month != second.month: - return cmp(first.month,second.month) - else: - return cmp(first.day,second.day) - return 0 diff --git a/src/DateDisplay.py b/src/DateDisplay.py new file mode 100644 index 000000000..0f5af1d61 --- /dev/null +++ b/src/DateDisplay.py @@ -0,0 +1,324 @@ +# -*- coding: iso-8859-1 -*- +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2004 Donald N. Allingham +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# $Id$ + +""" +U.S English date display class. Should serve as the base class for all +localized tasks. +""" + +__author__ = "Donald N. Allingham" +__version__ = "$Revision$" + +import Date + +class DateDisplay: + """ + U.S English date display class. + """ + + formats = ( + "YYYY-MM-DD", + "MM/DD/YYYY", + "Month Day, Year", + "MON DAY, YEAR", + "Day Month Year", + "DAY MON YEAR" + ) + + _calendar = ( + "", + " (Julian)", + " (Hebrew)", + " (French Republican)", + " (Persian)", + " (Islamic)" + ) + + _mod_str = ( + "", + "before ", + "after ", + "about ", + "estimated ", + "calculated ", + "" + ) + + _months = ( + "", + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" + ) + + _MONS = ( + "", + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC" + ) + + _hebrew = ( + "", + "Tishri", + "Heshvan", + "Kislev", + "Tevet", + "Shevat", + "AdarI", + "AdarII", + "Nisan", + "Iyyar", + "Sivan", + "Tammuz", + "Av", + "Elul" + ) + + _french = ( + unicode("Vendémiaire",'latin-1'), + unicode("Brumaire",'latin-1'), + unicode("Frimaire",'latin-1'), + unicode("Nivôse",'latin-1'), + unicode("Pluviôse",'latin-1'), + unicode("Ventôse",'latin-1'), + unicode("Germinal",'latin-1'), + unicode("Floréal",'latin-1'), + unicode("Prairial",'latin-1'), + unicode("Messidor",'latin-1'), + unicode("Thermidor",'latin-1'), + unicode("Fructidor",'latin-1'), + unicode("Extra",'latin-1'), + ) + + _persian = ( + "Farvardin", + "Ordibehesht", + "Khordad", + "Tir", + "Mordad", + "Shahrivar", + "Mehr", + "Aban", + "Azar", + "Dey", + "Bahman", + "Esfand" + ) + + _islamic = ( + "Muharram", + "Safar", + "Rabi`al-Awwal", + "Rabi`ath-Thani", + "Jumada l-Ula", + "Jumada t-Tania", + "Rajab", + "Sha`ban", + "Ramadan", + "Shawwal", + "Dhu l-Qa`da", + "Dhu l-Hijja" + ) + + def __init__(self,format=None): + """ + Creates a DateDisplay class that converts a Date object to a string + of the desired format. The format value must correspond to the format + list value (DateDisplay.format[]). + """ + self.verify_format(format) + if format == None: + self.format = 0 + else: + self.format = format + + self.display_cal = [ + self._display_gregorian, + self._display_julian, + self._display_hebrew, + self._display_french, + self._display_persian, + self._display_islamic, + ] + + def verify_format(self,format): + """ + Verifies that the format value is within the correct range. + """ + assert(format < len(self.formats)) + + def quote_display(self,date): + """ + Similar to the display task, except that if the value is a text only + value, it is enclosed in quotes. + """ + if date.get_modifier() == Date.MOD_TEXTONLY: + return '"%s"' % self.display(date) + else: + return self.display(date) + + def text_display(self,date): + """ + Similar to the display task, except that if the value is a text only + value, it is enclosed in quotes. + """ + return date.get_text() + + def display(self,date): + """ + Returns a text string representing the date. + """ + mod = date.get_modifier() + cal = date.get_calendar() + start = date.get_start_date() + if start == Date.EMPTY: + return u"" + if mod == Date.MOD_SPAN: + d1 = self.display_cal[cal](start) + d2 = self.display_cal[cal](date.get_stop_date()) + return "from %s to %s%s" % (d1,d2,self._calendar[cal]) + elif mod == Date.MOD_RANGE: + d1 = self.display_cal[cal](start) + d2 = self.display_cal[cal](date.get_stop_date()) + return "between %s and %s%s" % (d1,d2,self._calendar[cal]) + else: + text = self.display_cal[date.get_calendar()](start) + return "%s%s%s" % (self._mod_str[mod],text,self._calendar[cal]) + + def _slash_year(self,val,slash): + if slash: + return "%d/%d" % (val,(val%10)+1) + else: + return str(val) + + def _display_gregorian(self,date_val): + year = self._slash_year(date_val[2],date_val[3]) + if self.format == 0: + # YYYY-MM-DD (ISO) + if date_val[0] == 0: + if date_val[1] == 0: + return year + else: + return "%s-%d" % (year,date_val[1]) + else: + return "%s-%d-%d" % (year,date_val[1],date_val[0]) + elif self.format == 1: + # MM/DD/YYYY (American numericalO) + if date_val[0] == 0: + if date_val[1] == 0: + return "%d" % date_val[2] + else: + return "%d/%d" % (date_val[1],date_val[2]) + else: + return "%d/%d/%d" % (date_val[1],date_val[0],date_val[2]) + elif self.format == 2: + # Month Day, Year + if date_val[0] == 0: + if date_val[1] == 0: + return year + else: + return "%s %s" % (self._months[date_val[1]],year) + else: + return "%s %d, %s" % (self._months[date_val[1]],date_val[0],year) + elif self.format == 3: + # MON Day, Year + if date_val[0] == 0: + if date_val[1] == 0: + return year + else: + return "%s %s" % (self._MONS[date_val[1]],year) + else: + return "%s %d, %s" % (self._MONS[date_val[1]],date_val[0],year) + elif self.format == 4: + # Day Month Year + if date_val[0] == 0: + if date_val[1] == 0: + return year + else: + return "%s %s" % (self._months[date_val[1]],year) + else: + return "%d %s %s" % (date_val[0],self._months[date_val[1]],year) + else: + # Day MON Year + if date_val[0] == 0: + if date_val[1] == 0: + return year + else: + return "%s %s" % (self._MONS[date_val[1]],year) + else: + return "%d %s %s" % (date_val[0],self._MONS[date_val[1]],year) + + def _display_julian(self,date_val): + # Julian date display is the same as Gregorian + return self._display_gregorian(date_val) + + def _display_calendar(self,date_val,month_list): + year = date_val[2] + if self.format == 0 or self.format == 1: + # YYYY-MM-DD (ISO) + if date_val[0] == 0: + if date_val[1] == 0: + return year + else: + return "%d-%d" % (year,date_val[1]) + else: + return "%d-%d-%d" % (year,date_val[1],date_val[0]) + else: + if date_val[0] == 0: + if date_val[1] == 0: + return year + else: + return "%s %d" % (month_list[date_val[1]],year) + else: + return "%s %d, %s" % (month_list[date_val[1]],date_val[0],year) + + def _display_french(self,date_val): + return self._display_calendar(date_val,self._french) + + def _display_hebrew(self,date_val): + return self._display_calendar(date_val,self._hebrew) + + def _display_persian(self,date_val): + return self._display_calendar(date_val,self._persian) + + def _display_islamic(self,date_val): + return self._display_calendar(date_val,self._islamic) + diff --git a/src/DateEdit.py b/src/DateEdit.py index 946c56ab2..730b7922a 100644 --- a/src/DateEdit.py +++ b/src/DateEdit.py @@ -43,6 +43,7 @@ import gtk.gdk # #------------------------------------------------------------------------- import Date +import DateParser import const #------------------------------------------------------------------------- @@ -60,15 +61,14 @@ class DateEdit: def __init__(self,text_obj,pixmap_obj): """Creates a connection between the text_obj and the pixmap_obj""" - + + self.dp = DateParser.DateParser() self.text_obj = text_obj self.pixmap_obj = pixmap_obj - self.checkval = Date.Date() self.text_obj.connect('focus-out-event',self.check) self.check(None,None) def set_calendar(self,cobj): - self.checkval.set_calendar_obj(cobj) self.check(None,None) def check(self,obj,val): @@ -76,11 +76,11 @@ class DateEdit: valid date, sets the appropriate pixmap""" text = unicode(self.text_obj.get_text()) - self.checkval.set(text) - if not self.checkval.is_valid(): + self.checkval = self.dp.parse(text) + if self.checkval.get_modifier() == Date.MOD_TEXTONLY: self.pixmap_obj.set_from_pixbuf(DateEdit.bad) - elif self.checkval.get_incomplete(): - self.pixmap_obj.set_from_pixbuf(DateEdit.caution) +# elif self.checkval.get_incomplete(): +# self.pixmap_obj.set_from_pixbuf(DateEdit.caution) else: self.pixmap_obj.set_from_pixbuf(DateEdit.good) diff --git a/src/DateHandler.py b/src/DateHandler.py new file mode 100644 index 000000000..40807f5ea --- /dev/null +++ b/src/DateHandler.py @@ -0,0 +1,60 @@ +import DateParser +import DateDisplay +import os + +try: + import gconf +except ImportError: + import gnome.gconf + gconf = gnome.gconf + +client = gconf.client_get_default() +client.add_dir("/apps/gramps",gconf.CLIENT_PRELOAD_NONE) + +_lang = os.environ.get('LANG','C') + + +_lang_to_parser = { + 'C' : DateParser.DateParser, + 'en.US' : DateParser.DateParser, + } + +_lang_to_display = { + 'C' : DateDisplay.DateDisplay, + 'en.US' : DateDisplay.DateDisplay, + } + +def create_parser(): + try: + return _lang_to_parser[_lang]() + except: + print "not found" + return DateParser.DateParser() + +def create_display(): + val = client.get_int("/apps/gramps/preferences/date-format") + try: + return _lang_to_display[_lang](val) + except: + return DateDisplay.DateDisplay(3) + +def get_date_formats(): + try: + return _lang_to_display[_lang].formats + except: + print "not found" + return DateDisplay.DateDisplay.formats + +def set_format(val): + try: + _lang_to_display[_lang].display_format = val + except: + print "not found" + pass + +def get_format(): + try: + return _lang_to_display[_lang].display_format + except: + print "not found" + return 0 diff --git a/src/DateParser.py b/src/DateParser.py new file mode 100644 index 000000000..d85047d24 --- /dev/null +++ b/src/DateParser.py @@ -0,0 +1,222 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2004 Donald N. Allingham +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +U.S. English date parsing class. Serves as the base class for any localized +date parsing class. +""" + +__author__ = "Donald N. Allingham" +__version__ = "$Revision$" + +import string +import re +import Date + +class DateParser: + """ + Converts a text string into a Date object. If the date cannot be + converted, the text string is assigned. + """ + month_to_int = { + 'jan' : 1, + 'january' : 1, + 'feb' : 2, + 'february' : 2, + 'mar' : 3, + 'march' : 3, + 'apr' : 4, + 'april' : 4, + 'may' : 5, + 'june' : 6, + 'jun' : 6, + 'july' : 7, + 'jul' : 7, + 'august' : 8, + 'aug' : 8, + 'september': 9, + 'sep' : 9, + 'sept' : 9, + 'oct' : 10, + 'october' : 10, + 'nov' : 11, + 'november' : 11, + 'dec' : 12, + 'december' : 12, + } + + modifier_to_int = { + 'before' : Date.MOD_BEFORE, + 'bef' : Date.MOD_BEFORE, + 'bef.' : Date.MOD_BEFORE, + 'after' : Date.MOD_AFTER, + 'aft' : Date.MOD_AFTER, + 'aft.' : Date.MOD_AFTER, + 'about' : Date.MOD_ABOUT, + 'abt.' : Date.MOD_ABOUT, + 'abt' : Date.MOD_ABOUT, + 'circa' : Date.MOD_ABOUT, + 'c.' : Date.MOD_ABOUT, + 'around' : Date.MOD_ABOUT, + } + + quality_to_int = { + 'estimated' : Date.QUAL_ESTIMATED, + 'est.' : Date.QUAL_ESTIMATED, + 'est' : Date.QUAL_ESTIMATED, + 'calc.' : Date.QUAL_CALCULATED, + 'calc' : Date.QUAL_CALCULATED, + 'calculated' : Date.QUAL_CALCULATED, + } + + _qual_str = '(' + string.join(quality_to_int.keys(),'|') + ')' + _mod_str = '(' + string.join(modifier_to_int.keys(),'|') + ')' + _mon_str = '(' + string.join(month_to_int.keys(),'|') + ')' + + _qual = re.compile("%s\s+(.*)" % _qual_str,re.IGNORECASE) + _span = re.compile("from\s+(.*)\s+to\s+(.*)",re.IGNORECASE) + _range = re.compile("(bet.|between)\s+(.*)\s+and\s+(.*)",re.IGNORECASE) + _modifier = re.compile('%s\s+(.*)' % _mod_str,re.IGNORECASE) + _text = re.compile('%s\s+(\d+)?\s*,?\s*((\d+)(/\d+)?)?' % _mon_str,re.IGNORECASE) + _text2 = re.compile('(\d+)?\s+?%s\s*((\d+)(/\d+)?)?' % _mon_str,re.IGNORECASE) + _numeric = re.compile("((\d+)[/\.])?((\d+)[/\.])?(\d+)") + _iso = re.compile("(\d+)-(\d+)-(\d+)") + + def _get_int(self,val): + """ + Converts the string to an integer if the value is not None. If the + value is None, a zero is returned + """ + if val == None: + return 0 + else: + return int(val) + + def _parse_subdate(self,text): + """ + Converts only the date portion of a date. + """ + match = self._text.match(text) + if match: + groups = match.groups() + if groups[0] == None: + m = 0 + else: + m = self.month_to_int[groups[0].lower()] + + d = self._get_int(groups[1]) + + if groups[2] == None: + y = 0 + s = None + else: + y = int(groups[3]) + s = groups[4] != None + return (d,m,y,s) + + match = self._text2.match(text) + if match: + groups = match.groups() + if groups[1] == None: + m = 0 + else: + m = self.month_to_int[groups[1].lower()] + + d = self._get_int(groups[0]) + + if groups[2] == None: + y = 0 + s = None + else: + y = int(groups[3]) + s = groups[4] != None + return (d,m,y,s) + + match = self._iso.match(text) + if match: + groups = match.groups() + y = self._get_int(groups[0]) + m = self._get_int(groups[1]) + d = self._get_int(groups[2]) + return (d,m,y,False) + + match = self._numeric.match(text) + if match: + groups = match.groups() + m = self._get_int(groups[1]) + d = self._get_int(groups[3]) + y = self._get_int(groups[4]) + return (d,m,y,False) + + return Date.EMPTY + + def set_date(self,date,text): + """ + Parses the text, returning a Date object. + """ + date.set_text_value(text) + qual = Date.QUAL_NONE + + match = self._qual.match(text) + if match: + grps = match.groups() + qual = self.quality_to_int[grps[0].lower()] + text = grps[1] + + match = self._span.match(text) + if match: + grps = match.groups() + start = self._parse_subdate(grps[0]) + stop = self._parse_subdate(grps[1]) + date.set_modifier(Date.MOD_SPAN) + date.set(qual,Date.MOD_SPAN,Date.CAL_GREGORIAN,start + stop) + return + + match = self._range.match(text) + if match: + grps = match.groups() + start = self._parse_subdate(grps[1]) + stop = self._parse_subdate(grps[2]) + date.set(qual,Date.MOD_RANGE,Date.CAL_GREGORIAN,start + stop) + return + + match = self._modifier.match(text) + if match: + grps = match.groups() + start = self._parse_subdate(grps[1]) + mod = self.modifier_to_int.get(grps[0].lower(),Date.MOD_NONE) + date.set(qual,mod,Date.CAL_GREGORIAN,start) + return date + + subdate = self._parse_subdate(text) + if subdate == Date.EMPTY: + date.set_as_text(text) + else: + date.set(qual,Date.MOD_NONE,Date.CAL_GREGORIAN,subdate) + + def parse(self,text): + """ + Parses the text, returning a Date object. + """ + new_date = Date.Date() + self.set_date(new_date,text) + return new_date + + diff --git a/src/EditPerson.py b/src/EditPerson.py index 0df7a4a80..7e0272994 100644 --- a/src/EditPerson.py +++ b/src/EditPerson.py @@ -55,6 +55,8 @@ import ListModel import RelLib import Sources import DateEdit +import DateParser +import DateHandler import TransTable from QuestionDialog import QuestionDialog, WarningDialog, ErrorDialog, SaveDialog @@ -88,6 +90,8 @@ class EditPerson: def __init__(self,parent,person,db,callback=None): """Creates an edit window. Associates a person with the window.""" + self.dp = DateHandler.create_parser() + self.dd = DateHandler.create_display() self.person = person self.orig_surname = person.get_primary_name().get_surname() self.parent = parent @@ -1208,14 +1212,12 @@ class EditPerson: self.redraw_event_list() def update_birth_death(self): - self.bdate.set_text(self.birth.get_date()) - self.bplace.set_text(place_title(self.db,self.birth)) self.dplace.set_text(place_title(self.db,self.death)) - self.bdate.set_text(self.birth.get_date()) + self.bdate.set_text(self.dd.display(self.birth.get_date_object())) self.bdate_check.set_calendar(self.birth.get_date_object().get_calendar()) - self.ddate.set_text(self.death.get_date()) + self.ddate.set_text(self.dd.display(self.death.get_date_object())) self.ddate_check.set_calendar(self.death.get_date_object().get_calendar()) def on_update_attr_clicked(self,obj): diff --git a/src/EventEdit.py b/src/EventEdit.py index c6debcdd4..6da051a6a 100644 --- a/src/EventEdit.py +++ b/src/EventEdit.py @@ -42,9 +42,10 @@ import const import Utils import GrampsCfg import AutoComp -import Calendar import RelLib import Date +import DateParser +import DateHandler import ImageSelect from DateEdit import DateEdit @@ -78,6 +79,9 @@ class EventEditor: self.plist = [] self.pmap = {} + self.dp = DateHandler.create_parser() + self.dd = DateHandler.create_display() + values = {} for v in elist: values[v] = 1 @@ -140,10 +144,7 @@ class EventEditor: self.gallery_label = self.top.get_widget("galleryEvent") self.witnesses_label = self.top.get_widget("witnessesEvent") - if GrampsCfg.get_calendar(): - self.calendar.show() - else: - self.calendar.hide() + self.calendar.show() if read_only: self.event_menu.set_sensitive(0) @@ -176,7 +177,7 @@ class EventEditor: place_name = self.db.get_place_from_handle(place_handle).get_title() self.place_field.set_text(place_name) - self.date_field.set_text(self.date.get_date()) + self.date_field.set_text(self.dd.display(self.date)) self.cause_field.set_text(event.get_cause()) self.descr_field.set_text(event.get_description()) self.priv.set_active(event.get_privacy()) @@ -219,16 +220,16 @@ class EventEditor: menu = gtk.Menu() index = 0 - for cobj in Calendar.calendar_names(): - item = gtk.MenuItem(cobj.TNAME) - item.set_data("d",cobj) + for cobj in Date.Date.calendar: + item = gtk.MenuItem(cobj) + item.set_data("d",index) item.connect("activate",self.on_menu_changed) item.show() menu.append(item) - if self.date.get_calendar().NAME == cobj.NAME: + if self.date.get_calendar() == index: menu.set_active(index) - self.date_check.set_calendar(cobj()) - index = index + 1 + self.date_check.set_calendar(index) + index += 1 self.calendar.set_menu(menu) self.window.set_transient_for(self.parent.window) @@ -285,10 +286,10 @@ class EventEditor: def on_menu_changed(self,obj): cobj = obj.get_data("d") - self.date.set(unicode(self.date_field.get_text())) + self.date = self.dp.parse(self.date_field.get_text()) self.date.set_calendar(cobj) - self.date_field.set_text(self.date.get_date()) - self.date_check.set_calendar(cobj()) + self.date_field.set_text(self.dd(self.date)) + self.date_check.set_calendar(cobj) def get_place(self,field,trans): text = strip(unicode(field.get_text())) @@ -305,7 +306,7 @@ class EventEditor: trans = self.db.transaction_begin() ename = unicode(self.event_menu.child.get_text()) - self.date.set(unicode(self.date_field.get_text())) + self.date = self.dp.parse(unicode(self.date_field.get_text())) ecause = unicode(self.cause_field.get_text()) eplace_obj = self.get_place(self.place_field,trans) buf = self.note_field.get_buffer() @@ -367,7 +368,7 @@ class EventEditor: self.event.set_source_reference_list(self.srcreflist) self.event.set_witness_list(self.witnesslist) - if Date.compare_dates(dobj,date) != 0: + if dobj != date: self.event.set_date_object(date) self.parent.lists_changed = 1 diff --git a/src/GrampsCfg.py b/src/GrampsCfg.py index ca7aaf746..6aeeae2eb 100644 --- a/src/GrampsCfg.py +++ b/src/GrampsCfg.py @@ -59,7 +59,7 @@ import const import Utils import PaperMenu import Plugins -import Calendar +import DateHandler client = gconf.client_get_default() client.add_dir("/apps/gramps",gconf.CLIENT_PRELOAD_NONE) @@ -96,12 +96,6 @@ _date_format_list = [ _("YYYY.MM.DD"), ] -_date_entry_list = [ - _("MM/DD/YYYY, MM.DD.YYYY, or MM-DD-YYYY"), - _("DD/MM/YYYY, DD.MM.YYYY, or DD-MM-YYYY"), - _("YYYY/MM/DD, YYYY.MM.DD, or YYYY-MM-DD"), - ] - _name_format_list = [ (_("Firstname Surname"), Utils.normal_name, Utils.phonebook_name, lambda x: x.get_surname()), (_("Surname, Firstname"), Utils.phonebook_name, Utils.phonebook_name, lambda x: x.get_surname()), @@ -113,10 +107,10 @@ panellist = [ (_("Database"), [( _("General"), 1), ( _("Media Objects"), 7), - ( _("GRAMPS internal IDs"), 8)]), + ( _("GRAMPS IDs"), 8)]), (_("Display"), [( _("General"), 3), - ( _("Dates and Calendars"), 4), + ( _("Dates and Names"), 4), ( _("Toolbar and Statusbar"), 2)]), (_("Usage"), [( _("Report Preferences"), 6), @@ -256,12 +250,6 @@ def get_media_local(): def save_media_local(val): set_bool("/apps/gramps/behavior/media-local",val) -def get_calendar(): - return get_bool("/apps/gramps/behavior/show-calendar") - -def save_calendar(val): - set_bool("/apps/gramps/behavior/show-calendar",val) - def get_lastnamegen(): return get_int("/apps/gramps/behavior/surname-guessing", range(len(_surname_styles))) @@ -343,14 +331,6 @@ def get_use_tips(): def save_use_tips(val): set_bool("/apps/gramps/preferences/use-tips",val) -def get_date_entry(): - return get_int("/apps/gramps/preferences/date-entry", - range(len(_date_entry_list))) - -def save_date_entry(val): - set_int("/apps/gramps/preferences/date-entry",val, - range(len(_date_entry_list))) - def get_date_format(): return get_int("/apps/gramps/preferences/date-format", range(len(_date_format_list))) @@ -440,10 +420,7 @@ def get_toolbar_style(): return gnome_toolbar def set_calendar_date_format(): - Calendar.set_format_code(get_date_format()) - -def set_calendar_date_entry(): - Calendar.Calendar.ENTRYCODE = get_date_entry() + DateHandler.set_format(get_date_format()) #------------------------------------------------------------------------- # @@ -749,11 +726,6 @@ class GrampsPreferences: dl.set_active(get_media_local()) dl.connect('toggled',lambda obj: save_media_local(obj.get_active())) - cal = self.top.get_widget("calendar") - cal.set_active(get_calendar()) - - cal.connect('toggled',lambda obj: save_calendar(obj.get_active())) - index_vis = self.top.get_widget("show_child_id") index_vis.set_active(get_index_visible()) index_vis.connect('toggled',lambda obj: save_index_visible(obj.get_active())) @@ -871,28 +843,17 @@ class GrampsPreferences: date_option = self.top.get_widget("date_format") date_menu = gtk.Menu() - for index in range(0,len(_date_format_list)): - item = gtk.MenuItem(_date_format_list[index]) + dlist = DateHandler.get_date_formats() + for index in range(0,len(dlist)): + item = gtk.MenuItem(dlist[index]) item.set_data(INDEX,index) item.show() date_menu.append(item) - date_menu.set_active(Calendar.get_format_code()) + date_menu.set_active(get_date_format()) date_option.set_menu(date_menu) date_option.connect("changed", lambda obj: save_date_format(obj.get_menu().get_active().get_data(INDEX))) - date_entry = self.top.get_widget("date_entry_format") - date_menu = gtk.Menu() - for index in range(0,len(_date_entry_list)): - item = gtk.MenuItem(_date_entry_list[index]) - item.set_data(INDEX,index) - item.show() - date_menu.append(item) - date_menu.set_active(Calendar.Calendar.ENTRYCODE) - date_entry.set_menu(date_menu) - date_entry.connect("changed", - lambda obj: save_date_entry(obj.get_menu().get_active().get_data(INDEX))) - name_option = self.top.get_widget("name_format") name_menu = gtk.Menu() for index in range(0,len(_name_format_list)): diff --git a/src/Gregorian.py b/src/Gregorian.py deleted file mode 100644 index 418688b88..000000000 --- a/src/Gregorian.py +++ /dev/null @@ -1,132 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001 Donald N. Allingham -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -""" -Gregorian calendar module for GRAMPS. - -The original algorithms for this module came from Scott E. Lee's -C implementation. The original C source can be found at Scott's -web site at http://www.scottlee.com -""" - -__author__ = "Donald N. Allingham" -__version__ = "$Revision$" - -#------------------------------------------------------------------------- -# -# Gramps Modules -# -#------------------------------------------------------------------------- -import Calendar -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# Gregorian -# -#------------------------------------------------------------------------- -class Gregorian(Calendar.Calendar): - """Gregorian Calendar""" - - SDN_OFFSET = 32045 - DAYS_PER_5_MONTHS = 153 - DAYS_PER_4_YEARS = 1461 - DAYS_PER_400_YEARS = 146097 - - NAME = "Gregorian" - TNAME = _("Gregorian") - - def quote_display(self,year,month,day,mode): - return self.display(year,month,day,mode) - - def mlen(self): - return 3 - - def get_ymd(self,sdn): - """Converts an SDN number to a gregorial date""" - if sdn <= 0: - return (0,0,0) - - temp = (Gregorian.SDN_OFFSET + sdn) * 4 - 1 - - # Calculate the century (year/100) - century = temp / Gregorian.DAYS_PER_400_YEARS - - # Calculate the year and day of year (1 <= dayOfYear <= 366) - - temp = ((temp % Gregorian.DAYS_PER_400_YEARS) / 4) * 4 + 3 - year = (century * 100) + (temp / Gregorian.DAYS_PER_4_YEARS) - dayOfYear = (temp % Gregorian.DAYS_PER_4_YEARS) / 4 + 1 - - # Calculate the month and day of month - temp = dayOfYear * 5 - 3 - month = temp / Gregorian.DAYS_PER_5_MONTHS - day = (temp % Gregorian.DAYS_PER_5_MONTHS) / 5 + 1 - - # Convert to the normal beginning of the year - if month < 10 : - month = month + 3 - else: - year = year + 1 - month = month - 9 - - # Adjust to the B.C./A.D. type numbering - - year = year - 4800 - if year <= 0: - year = year - 1 - - return (year,month,day) - - def get_sdn(self,iyear,imonth,iday): - """Converts a gregorian date to an SDN number""" - # check for invalid dates - if iyear==0 or iyear<-4714 or imonth<=0 or imonth>12 or iday<=0 or iday>31: - return 0 - - # check for dates before SDN 1 (Nov 25, 4714 B.C.) - if iyear == -4714: - if imonth < 11 or imonth == 11 and iday < 25: - return 0 - - if iyear < 0: - year = iyear + 4801 - else: - year = iyear + 4800 - - # Adjust the start of the year - - if imonth > 2: - month = imonth - 3 - else: - month = imonth + 9 - year = year - 1 - - return( ((year / 100) * Gregorian.DAYS_PER_400_YEARS) / 4 - + ((year % 100) * Gregorian.DAYS_PER_4_YEARS) / 4 - + (month * Gregorian.DAYS_PER_5_MONTHS + 2) / 5 - + iday - - Gregorian.SDN_OFFSET ); - - def check(self,year,month,day): - if year > 2100 or month > 12 or day > 31: - return 0 - return 1 - -Calendar.register(Gregorian) diff --git a/src/Hebrew.py b/src/Hebrew.py deleted file mode 100644 index b9422ae2a..000000000 --- a/src/Hebrew.py +++ /dev/null @@ -1,390 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001 Donald N. Allingham -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -""" -Gregorian calendar module for GRAMPS. - -The original algorithms for this module came from Scott E. Lee's -C implementation. The original C source can be found at Scott's -web site at http://www.scottlee.com -""" - -__author__ = "Donald N. Allingham" -__version__ = "$Revision$" - -#------------------------------------------------------------------------- -# -# Gramps Modules -# -#------------------------------------------------------------------------- -import Calendar -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# Hebrew calendar -# -#------------------------------------------------------------------------- -class Hebrew(Calendar.Calendar): - """Jewish Calendar""" - - HALAKIM_PER_HOUR = 1080 - HALAKIM_PER_DAY = 25920 - HALAKIM_PER_LUNAR_CYCLE = ((29 * HALAKIM_PER_DAY) + 13753) - HALAKIM_PER_METONIC_CYCLE = (HALAKIM_PER_LUNAR_CYCLE * (12 * 19 + 7)) - - SDN_OFFSET = 347997 - NEW_MOON_OF_CREATION = 31524 - - SUNDAY = 0 - MONDAY = 1 - TUESDAY = 2 - WEDNESDAY= 3 - FRIDAY = 5 - - NOON = (18 * HALAKIM_PER_HOUR) - AM3_11_20 = ((9 * HALAKIM_PER_HOUR) + 204) - AM9_32_43 = ((15 * HALAKIM_PER_HOUR) + 589) - - monthsPerYear = [ - 12, 12, 13, 12, 12, 13, 12, 13, 12, 12, - 13, 12, 12, 13, 12, 12, 13, 12, 13 ] - - yearOffset = [ - 0, 12, 24, 37, 49, 61, 74, 86, 99, 111, 123, - 136, 148, 160, 173, 185, 197, 210, 222 ] - - MONTHS = [ - "Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "AdarI", - "AdarII", "Nisan", "Iyyar", "Sivan", "Tammuz", "Av", - "Elul",] - - M2NUM = { - "tishri" : 1, "heshvan" : 2, "kislev" : 3, "tevet" : 4, - "shevat" : 5, "adari" : 6, "adarii" : 7, "nisan" : 8, - "iyyar" : 9, "sivan" :10, "tammuz" :11, "av" : 12, - "elul" : 13,"tsh" : 1, "csh" : 2, "ksl" : 3, - "tvt" : 4, "shv" : 5, "adr" : 6, "ads" : 7, - "nsn" : 8, "iyr" : 9, "svn" :10, "tmz" : 11, - "aav" :12, "ell" :13, - } - - NAME = "Hebrew" - TNAME = _("Hebrew") - - def quote_display(self,year,month,day,mode): - return "%s (%s)" % (self.display(year,month,day,mode),Hebrew.NAME) - - def month(self,val): - try: - return Hebrew.MONTHS[val-1] - except: - return "Illegal Month" - - def set_month_string(self,text): - try: - return Hebrew.M2NUM[unicode(text.lower())] - except KeyError: - return Calendar.UNDEF - - def Tishri1(self,metonicYear, moladDay, moladHalakim): - - tishri1 = moladDay - dow = tishri1 % 7 - leapYear = metonicYear in [ 2, 5, 7, 10, 13, 16, 18] - lastWasLeapYear = metonicYear in [ 3, 6, 8, 11, 14, 17, 0] - - # Apply rules 2, 3 and 4. - if ((moladHalakim >= Hebrew.NOON) or - ((not leapYear) and dow == Hebrew.TUESDAY and - moladHalakim >= Hebrew.AM3_11_20) or - (lastWasLeapYear and dow == Hebrew.MONDAY and moladHalakim >= Hebrew.AM9_32_43)) : - tishri1 = tishri1 + 1 - dow = dow + 1 - if dow == 7: - dow = 0 - - # Apply rule 1 after the others because it can cause an additional - # delay of one day - - if dow == Hebrew.WEDNESDAY or dow == Hebrew.FRIDAY or dow == Hebrew.SUNDAY: - tishri1 = tishri1 + 1 - - return tishri1 - - def MoladOfMetonicCycle(self,metonicCycle): - - # Start with the time of the first molad after creation. - - r1 = Hebrew.NEW_MOON_OF_CREATION - - # Calculate metonicCycle * HALAKIM_PER_METONIC_CYCLE. The upper 32 - # bits of the result will be in r2 and the lower 16 bits will be - # in r1. - - r1 = r1 + (metonicCycle * (Hebrew.HALAKIM_PER_METONIC_CYCLE & 0xFFFF)) - r2 = r1 >> 16 - r2 = r2 + (metonicCycle * ((Hebrew.HALAKIM_PER_METONIC_CYCLE >> 16) & 0xFFFF)) - - # Calculate r2r1 / HALAKIM_PER_DAY. The remainder will be in r1, the - # upper 16 bits of the quotient will be in d2 and the lower 16 bits - # will be in d1. - - d2 = r2 / Hebrew.HALAKIM_PER_DAY - r2 = r2 - (d2 * Hebrew.HALAKIM_PER_DAY) - r1 = (r2 << 16) | (r1 & 0xFFFF) - d1 = r1 / Hebrew.HALAKIM_PER_DAY - r1 = r1 - ( d1 * Hebrew.HALAKIM_PER_DAY) - - MoladDay = (d2 << 16) | d1 - MoladHalakim = r1 - - return (MoladDay,MoladHalakim) - - def TishriMolad(self,inputDay): - - # Estimate the metonic cycle number. Note that this may be an under - # estimate because there are 6939.6896 days in a metonic cycle not - # 6940, but it will never be an over estimate. The loop below will - # correct for any error in this estimate. */ - - metonicCycle = (inputDay + 310) / 6940 - - # Calculate the time of the starting molad for this metonic cycle. */ - - (moladDay, moladHalakim) = self.MoladOfMetonicCycle(metonicCycle) - - # If the above was an under estimate, increment the cycle number until - # the correct one is found. For modern dates this loop is about 98.6% - # likely to not execute, even once, because the above estimate is - # really quite close. - - while moladDay < (inputDay - 6940 + 310): - metonicCycle = metonicCycle + 1 - moladHalakim = moladHalakim + Hebrew.HALAKIM_PER_METONIC_CYCLE - moladDay = moladDay + ( moladHalakim / Hebrew.HALAKIM_PER_DAY) - moladHalakim = moladHalakim % Hebrew.HALAKIM_PER_DAY - - # Find the molad of Tishri closest to this date. - - for metonicYear in range(0,18): - if moladDay > inputDay - 74: - break - - moladHalakim = moladHalakim + \ - (Hebrew.HALAKIM_PER_LUNAR_CYCLE * Hebrew.monthsPerYear[metonicYear]) - moladDay = moladDay + (moladHalakim / Hebrew.HALAKIM_PER_DAY) - moladHalakim = moladHalakim % Hebrew.HALAKIM_PER_DAY - else: - metonicYear = metonicYear + 1 - return (metonicCycle, metonicYear, moladDay, moladHalakim) - - def StartOfYear(self,year): - - MetonicCycle = (year - 1) / 19; - MetonicYear = (year - 1) % 19; - (MoladDay, MoladHalakim) = self.MoladOfMetonicCycle(MetonicCycle) - - MoladHalakim = MoladHalakim + (Hebrew.HALAKIM_PER_LUNAR_CYCLE * Hebrew.yearOffset[MetonicYear]) - MoladDay = MoladDay + (MoladHalakim / Hebrew.HALAKIM_PER_DAY) - MoladHalakim = MoladHalakim % Hebrew.HALAKIM_PER_DAY - - pTishri1 = self.Tishri1(MetonicYear, MoladDay, MoladHalakim); - - return (MetonicCycle, MetonicYear, MoladDay, MoladHalakim, pTishri1) - - def get_ymd(self,sdn): - """Converts an SDN number to a Julian calendar date""" - - if sdn <= Hebrew.SDN_OFFSET : - return (0,0,0) - - inputDay = sdn - Hebrew.SDN_OFFSET - - (metonicCycle, metonicYear, day, halakim) = self.TishriMolad(inputDay) - tishri1 = self.Tishri1(metonicYear, day, halakim); - - if inputDay >= tishri1: - # It found Tishri 1 at the start of the year - - Year = (metonicCycle * 19) + metonicYear + 1 - if inputDay < tishri1 + 59: - if inputDay < tishri1 + 30: - Month = 1 - Day = inputDay - tishri1 + 1 - else: - Month = 2 - Day = inputDay - tishri1 - 29 - return (Year, Month, Day) - - # We need the length of the year to figure this out, so find - # Tishri 1 of the next year. */ - - halakim = halakim + (Hebrew.HALAKIM_PER_LUNAR_CYCLE * Hebrew.monthsPerYear[metonicYear]) - day = day + (halakim / Hebrew.HALAKIM_PER_DAY) - halakim = halakim % Hebrew.HALAKIM_PER_DAY; - tishri1After = self.Tishri1((metonicYear + 1) % 19, day, halakim); - else: - # It found Tishri 1 at the end of the year. - - Year = metonicCycle * 19 + metonicYear - if inputDay >= tishri1 - 177: - # It is one of the last 6 months of the year. - if inputDay > tishri1 - 30: - Month = 13 - Day = inputDay - tishri1 + 30 - elif inputDay > tishri1 - 60: - Month = 12 - Day = inputDay - tishri1 + 60 - elif inputDay > tishri1 - 89: - Month = 11 - Day = inputDay - tishri1 + 89 - elif inputDay > tishri1 - 119: - Month = 10 - Day = inputDay - tishri1 + 119 - elif inputDay > tishri1 - 148: - Month = 9 - Day = inputDay - tishri1 + 148 - else: - Month = 8 - Day = inputDay - tishri1 + 178 - return (Year,Month,Day) - else: - if Hebrew.monthsPerYear[(Year - 1) % 19] == 13: - Month = 7 - Day = inputDay - tishri1 + 207 - if Day > 0: - return (Year,Month,Day) - Month = Month - 1 - Day = Day + 30 - if Day > 0: - return (Year,Month,Day) - Month = Month - 1 - Day = Day + 30 - else: - Month = 6 - Day = inputDay - tishri1 + 207 - if Day > 0: - return (Year,Month,Day) - Month = Month - 1 - Day = Day + 30 - - if Day > 0: - return (Year,Month,Day) - Month = Month - 1 - Day = Day + 29 - if Day > 0: - return (Year,Month,Day) - - # We need the length of the year to figure this out, so find - # Tishri 1 of this year - tishri1After = tishri1; - (metonicCycle,metonicYear,day,halakim) = self.TishriMolad(day-365) - tishri1 = self.Tishri1(metonicYear, day, halakim) - - yearLength = tishri1After - tishri1; - cday = inputDay - tishri1 - 29; - if yearLength == 355 or yearLength == 385 : - # Heshvan has 30 days - if day <= 30: - Month = 2 - Day = cday - return (Year,Month,Day) - day = day - 30 - else: - # Heshvan has 29 days - if day <= 29: - Month = 2 - Day = cday - return (Year,Month,Day) - - cday = cday - 29 - - # It has to be Kislev - return (Year,3,cday) - - def get_sdn(self,year, month, day): - """Converts a Jewish calendar date to an SDN number""" - if year <= 0 or day <= 0 or day > 30 : - return 0 - - if month == 1 or month == 2: - # It is Tishri or Heshvan - don't need the year length. - (metonicCycle,metonicYear,moladDay,moladHalakim,tishri1) = self.StartOfYear(year) - if month == 1: - sdn = tishri1 + day - 1 - else: - sdn = tishri1 + day + 29 - elif month == 3: - # It is Kislev - must find the year length. - - # Find the start of the year. - (metonicCycle,metonicYear,moladDay,moladHalakim,tishri1) = self.StartOfYear(year) - - # Find the end of the year. - moladHalakim = moladHalakim + (Hebrew.HALAKIM_PER_LUNAR_CYCLE*Hebrew.monthsPerYear[metonicYear]) - moladDay = moladDay + (moladHalakim / Hebrew.HALAKIM_PER_DAY) - moladHalakim = moladHalakim % Hebrew.HALAKIM_PER_DAY - tishri1After = self.Tishri1((metonicYear + 1) % 19, moladDay, moladHalakim) - - yearLength = tishri1After - tishri1 - - if yearLength == 355 or yearLength == 385: - sdn = tishri1 + day + 59 - else: - sdn = tishri1 + day + 58 - elif month == 4 or month == 5 or month == 6: - # It is Tevet, Shevat or Adar I - don't need the year length - - (metonicCycle,metonicYear,moladDay,moladHalakim,tishri1After) = self.StartOfYear(year+1) - - if Hebrew.monthsPerYear[(year - 1) % 19] == 12: - lengthOfAdarIAndII = 29 - else: - lengthOfAdarIAndII = 59 - - if month == 4: - sdn = tishri1After + day - lengthOfAdarIAndII - 237 - elif month == 5: - sdn = tishri1After + day - lengthOfAdarIAndII - 208 - else: - sdn = tishri1After + day - lengthOfAdarIAndII - 178 - else: - # It is Adar II or later - don't need the year length. - (metonicCycle,metonicYear,moladDay,moladHalakim,tishri1After) = self.StartOfYear(year+1) - - if month == 7: - sdn = tishri1After + day - 207 - elif month == 8: - sdn = tishri1After + day - 178 - elif month == 9: - sdn = tishri1After + day - 148 - elif month == 10: - sdn = tishri1After + day - 119 - elif month == 11: - sdn = tishri1After + day - 89 - elif month == 12: - sdn = tishri1After + day - 60 - elif month == 13: - sdn = tishri1After + day - 30 - else: - return 0 - return sdn + Hebrew.SDN_OFFSET - -Calendar.register(Hebrew) diff --git a/src/Julian.py b/src/Julian.py deleted file mode 100644 index f9864f994..000000000 --- a/src/Julian.py +++ /dev/null @@ -1,119 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001 Donald N. Allingham -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -""" -Gregorian calendar module for GRAMPS. - -The original algorithms for this module came from Scott E. Lee's -C implementation. The original C source can be found at Scott's -web site at http://www.scottlee.com -""" - -__author__ = "Donald N. Allingham" -__version__ = "$Revision$" - -#------------------------------------------------------------------------- -# -# Gramps Modules -# -#------------------------------------------------------------------------- -import Calendar -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# Julian -# -#------------------------------------------------------------------------- -class Julian(Calendar.Calendar): - """Julian calendar""" - - SDN_OFFSET = 32083 - DAYS_PER_5_MONTHS = 153 - DAYS_PER_4_YEARS = 1461 - - NAME = "Julian" - TNAME = _("Julian") - - def quote_display(self,year,month,day,mode): - return "%s (%s)" % (self.display(year,month,day,mode),Julian.NAME) - - def mlen(self): - return 3 - - def get_ymd(self,sdn): - """Converts an SDN number to a Julian date""" - if sdn <= 0 : - return (0,0,0) - - temp = (sdn + Julian.SDN_OFFSET) * 4 - 1 - - # Calculate the year and day of year (1 <= dayOfYear <= 366) - year = temp / Julian.DAYS_PER_4_YEARS - dayOfYear = (temp % Julian.DAYS_PER_4_YEARS) / 4 + 1 - - # Calculate the month and day of month - temp = dayOfYear * 5 - 3; - month = temp / Julian.DAYS_PER_5_MONTHS; - day = (temp % Julian.DAYS_PER_5_MONTHS) / 5 + 1; - - # Convert to the normal beginning of the year - if month < 10: - month = month + 3 - else: - year = year + 1 - month = month - 9 - - # Adjust to the B.C./A.D. type numbering - year = year - 4800 - if year <= 0: - year = year - 1 - - return (year,month,day) - - def get_sdn(self,iyear,imonth,iday): - """Converts a Julian calendar date to an SDN number""" - - # check for invalid dates - if iyear==0 or iyear<-4713 or imonth<=0 or imonth>12 or iday<=0 or iday>31: - return 0 - - # check for dates before SDN 1 (Jan 2, 4713 B.C.) - if iyear == -4713: - if imonth == 1 and iday == 1: - return 0 - - # Make year always a positive number - if iyear < 0: - year = iyear + 4801 - else: - year = iyear + 4800 - - # Adjust the start of the year - if imonth > 2: - month = imonth - 3 - else: - month = imonth + 9 - year = year - 1 - - return (year*Julian.DAYS_PER_4_YEARS)/4 + \ - (month*Julian.DAYS_PER_5_MONTHS+2)/5 + \ - iday - Julian.SDN_OFFSET - -Calendar.register(Julian) diff --git a/src/Makefile.am b/src/Makefile.am index b7ca225b4..46e7b27df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ # This is the src level Makefile for Gramps -SUBDIRS = docgen plugins data po calendars +SUBDIRS = docgen plugins data po # For intl. support, how do we compile? MOSTLYCLEANFILES = @@ -22,12 +22,15 @@ gdir_PYTHON = \ AutoComp.py\ BaseDoc.py\ Bookmarks.py\ - Calendar.py\ + CalSdn.py\ ColumnOrder.py\ ChooseParents.py\ const.py\ DateEdit.py\ Date.py\ + DateParser.py\ + DateHandler.py\ + DateDisplay.py\ DbPrompter.py\ DisplayModels.py\ DisplayTrace.py\ @@ -38,7 +41,6 @@ gdir_PYTHON = \ EventEdit.py\ FamilyView.py\ FontScale.py\ - FrenchRepublic.py\ GedcomInfo.py\ GenericFilter.py\ GrampsCfg.py\ @@ -50,11 +52,8 @@ gdir_PYTHON = \ gramps_main.py\ gramps.py\ GraphLayout.py\ - Gregorian.py\ - Hebrew.py\ ImageSelect.py\ ImgManip.py\ - Julian.py\ latin_ansel.py\ latin_utf8.py\ ListModel.py\ diff --git a/src/ReadGedcom.py b/src/ReadGedcom.py index 27286956c..5bf1ea04f 100644 --- a/src/ReadGedcom.py +++ b/src/ReadGedcom.py @@ -52,6 +52,7 @@ import Julian import FrenchRepublic import Hebrew import Date +import DateParser from ansel_utf8 import ansel_to_utf8 import latin_utf8 import Utils @@ -115,7 +116,8 @@ headRE = re.compile(r"\s*(\d+)\s+HEAD") nameRegexp= re.compile(r"/?([^/]*)(/([^/]*)(/([^/]*))?)?") snameRegexp= re.compile(r"/([^/]*)/([^/]*)") calRegexp = re.compile(r"\s*(ABT|BEF|AFT)?\s*@#D([^@]+)@\s*(.*)$") -fromtoRegexp = re.compile(r"\s*(FROM|BET)\s+@#D([^@]+)@\s*(.*)\s+(AND|TO)\s+@#D([^@]+)@\s*(.*)$") +rangeRegexp = re.compile(r"\s*BET\s+@#D([^@]+)@\s*(.*)\s+AND\s+@#D([^@]+)@\s*(.*)$") +spanRegexp = re.compile(r"\s*FROM\s+@#D([^@]+)@\s*(.*)\s+TO\s+@#D([^@]+)@\s*(.*)$") #------------------------------------------------------------------------- # @@ -204,6 +206,7 @@ class GedcomParser: BadFile = "Not a GEDCOM file" def __init__(self, dbase, file, window): + self.dp = DateParser.DateParser() self.db = dbase self.person = None self.fmap = {} @@ -1418,8 +1421,7 @@ class GedcomParser: source.set_page(matches[2] + self.parse_continue_data(level+1)) elif matches[1] == "DATA": date,text = self.parse_source_data(level+1) - d = Date.Date() - d.set(date) + d = self.dp.parse(date) source.set_date(d) source.set_text(text) elif matches[1] in ["OBJE","REFN","TEXT"]: @@ -1711,40 +1713,67 @@ class GedcomParser: def extract_date(self,text): dateobj = Date.Date() try: - match = fromtoRegexp.match(text) + match = rangeRegexp.match(text) if match: (cal1,data1,cal2,data2) = match.groups() if cal1 != cal2: pass if cal1 == "FRENCH R": - dateobj.set_calendar(FrenchRepublic.FrenchRepublic) + cal = Date.CAL_FRENCH elif cal1 == "JULIAN": - dateobj.set_calendar(Julian.Julian) + cal = Date.CAL_JULIAN elif cal1 == "HEBREW": - dateobj.set_calendar(Hebrew.Hebrew) - dateobj.get_start_date().set(data1) - dateobj.get_stop_date().set(data2) - dateobj.set_range(1) + cal = Date.CAL_HEBREW + else: + cal = Date.CAL_GREGORIAN + + start = self.dp.parse(data1) + stop = self.dp.parse(data2) + dateobj.set(Date.QUAL_NONE, Date.MOD_RANGE, cal, + start.get_start_date() + stop.get_start_date()) + print dateobj + return dateobj + + match = spanRegexp.match(text) + if match: + (cal1,data1,cal2,data2) = match.groups() + if cal1 != cal2: + pass + + if cal1 == "FRENCH R": + cal = Date.CAL_FRENCH + elif cal1 == "JULIAN": + cal = Date.CAL_JULIAN + elif cal1 == "HEBREW": + cal = Date.CAL_HEBREW + else: + cal = Date.CAL_GREGORIAN + + start = self.dp.parse(data1) + stop = self.dp.parse(data2) + dateobj.set(Date.QUAL_NONE, Date.MOD_SPAN, cal, + start.get_start_date() + stop.get_start_date()) + print dateobj return dateobj match = calRegexp.match(text) if match: (abt,cal,data) = match.groups() + dateobj = self.dp.parse("%s %s" % (abt, data)) if cal == "FRENCH R": - dateobj.set_calendar(FrenchRepublic.FrenchRepublic) + dateobj.set_calendar(Date.CAL_FRENCH) elif cal == "JULIAN": - dateobj.set_calendar(Julian.Julian) + dateobj.set_calendar(Date.CAL_JULIAN) elif cal == "HEBREW": - dateobj.set_calendar(Hebrew.Hebrew) - dateobj.set(data) - if abt: - dateobj.get_start_date().setMode(abt) + dateobj.set_calendar(Date.CAL_HEBREW) + print dateobj + return dateobj else: - dateobj.set(text) - except: - dateobj.set_text(text) - return dateobj + print text, self.dp.parse(text) + return self.dp.parse(text) + except IOError: + return self.dp.set_text(text) def handle_source(self,matches,level): source_ref = RelLib.SourceRef() diff --git a/src/ReadXML.py b/src/ReadXML.py index 24832a90f..c5d78c863 100644 --- a/src/ReadXML.py +++ b/src/ReadXML.py @@ -39,12 +39,12 @@ import time # #------------------------------------------------------------------------- from QuestionDialog import ErrorDialog, WarningDialog, MissingMediaDialog -import Calendar import Date import GrampsMime import RelLib import const import Utils +import DateHandler #------------------------------------------------------------------------- # @@ -287,6 +287,7 @@ class GrampsParser: self.gid2oid = {} self.gid2sid = {} self.change = change + self.dp = DateHandler.create_parser() self.ord = None self.objref = None @@ -723,7 +724,7 @@ class GrampsParser: def start_people(self,attrs): if attrs.has_key('home'): self.home = attrs['home'] - if attrs.has_key("default"): + elif attrs.has_key("default"): self.tempDefault = attrs["default"] def start_father(self,attrs): @@ -955,58 +956,110 @@ class GrampsParser: def start_daterange(self,attrs): if self.source_ref: - d = self.source_ref.get_date() + dv = self.source_ref.get_date() elif self.ord: - d = self.ord.get_date_object() + dv = self.ord.get_date_object() elif self.address: - d = self.address.get_date_object() + dv = self.address.get_date_object() else: - d = self.event.get_date_object() + dv = self.event.get_date_object() - if attrs.has_key("calendar"): - d.set_calendar_val(int(attrs['calendar'])) + start = attrs['start'].split('-') + stop = attrs['stop'].split('-') + + try: + y = int(start[0]) + except ValueError: + y = 0 + + try: + m = int(start[1]) + except: + m = 0 + + try: + d = int(start[2]) + except: + d = 0 + + try: + ry = int(stop[0]) + except: + ry = 0 + + try: + rm = int(stop[1]) + except: + rm = 0 + + try: + rd = int(stop[2]) + except: + rd = 0 if attrs.has_key("cformat"): - d.set_calendar(Calendar.find_calendar(attrs['calendar'])) + cal = Date.Date.calendar.index(attrs['calendar']) + else: + cal = Date.CAL_GREGORIAN + + dv.set(Date.QUAL_NONE,Date.MOD_RANGE,cal,(d,m,y,False,rd,rm,ry,False)) - d.get_start_date().set_iso_date(attrs['start']) - d.get_stop_date().set_iso_date(attrs['stop']) - d.range = 1 - def start_dateval(self,attrs): if self.source_ref: - d = self.source_ref.get_date() + dv = self.source_ref.get_date() elif self.ord: - d = self.ord.get_date_object() + dv = self.ord.get_date_object() elif self.address: - d = self.address.get_date_object() + dv = self.address.get_date_object() else: - d = self.event.get_date_object() + dv = self.event.get_date_object() - if attrs.has_key("calendar"): - d.set_calendar_val(int(attrs['calendar'])) + start = attrs['val'].split('-') + + try: + y = int(start[0]) + except: + y = 0 + + try: + m = int(start[1]) + except: + m = 0 + + try: + d = int(start[2]) + except: + d = 0 if attrs.has_key("cformat"): - d.set_calendar(Calendar.find_calendar(attrs['cformat'])) - - d.get_start_date().set_iso_date(attrs['val']) - - if attrs.has_key("type"): - d.get_start_date().set_mode(attrs['type']) + cal = Date.Date.calendar.index(attrs['calendar']) else: - d.get_start_date().set_mode(None) + cal = Date.CAL_GREGORIAN + + if attrs.has_key('type'): + val = attrs['type'] + if val == "about": + mod = Date.MOD_ABOUT + elif val == "after": + mod = Date.MOD_AFTER + else: + mod = Date.MOD_BEFORE + else: + mod = Date.MOD_NONE + + dv.set(Date.QUAL_NONE,mod,cal,(d,m,y,False)) def start_datestr(self,attrs): if self.source_ref: - d = self.source_ref.get_date() + dv = self.source_ref.get_date() elif self.ord: - d = self.ord.get_date_object() + dv = self.ord.get_date_object() elif self.address: - d = self.address.get_date_object() + dv = self.address.get_date_object() else: - d = self.event.get_date_object() + dv = self.event.get_date_object() - d.set(attrs['val']) + dv.set_as_text(attrs['val']) def start_created(self,attrs): if attrs.has_key('sources'): diff --git a/src/RelLib.py b/src/RelLib.py index ee7d9f021..9b13107d5 100644 --- a/src/RelLib.py +++ b/src/RelLib.py @@ -42,7 +42,9 @@ from gettext import gettext as _ # GRAMPS modules # #------------------------------------------------------------------------- -from Date import Date, SingleDate, compare_dates, not_too_old +import Date +import DateParser +import DateHandler import GrampsCfg import const import Utils @@ -548,7 +550,9 @@ class Person(PrimaryObject,SourceNote): for ev_handle in self.event_list: ev = db.get_event_from_handle(ev_handle) if ev.name in ["Cause Of Death", "Burial", "Cremation"]: - return 0 + return False + + return True if self.birth_handle: birth = db.get_event_from_handle(self.birth_handle) @@ -812,10 +816,12 @@ class Event(PrimaryObject,DataObj): PrimaryObject.__init__(self,source) DataObj.__init__(self,source) - + + self.dd = DateHandler.create_display() + self.dp = DateHandler.create_parser() if source: self.place = source.place - self.date = Date(source.date) + self.date = Date.Date(source.date) self.description = source.description self.name = source.name self.cause = source.cause @@ -917,7 +923,7 @@ class Event(PrimaryObject,DataObj): if (self.name != other.name or self.place != other.place or self.description != other.description or self.cause != other.cause or self.private != other.private or - compare_dates(self.get_date_object(),other.get_date_object()) or + self.get_date_object() != other.get_date_object() or len(self.get_source_references()) != len(other.get_source_references())): return 0 @@ -978,33 +984,29 @@ class Event(PrimaryObject,DataObj): def set_date(self, date) : """attempts to sets the date of the Event instance""" - if not self.date: - self.date = Date() - self.date.set(date) + self.date = self.dp.parse(date) def get_date(self) : """returns a string representation of the date of the Event instance""" if self.date: - return self.date.get_date() - return "" + return self.dd.display(self.date) + return u"" def get_preferred_date(self) : """returns a string representation of the date of the Event instance""" - if self.date: - return self.date.get_date() - return "" + return self.get_date() def get_quote_date(self) : """returns a string representation of the date of the Event instance, enclosing the results in quotes if it is not a valid date""" if self.date: - return self.date.get_quote_date() - return "" + return self.dd.quote_display(self.date) + return u"" def get_date_object(self): """returns the Date object associated with the Event""" if not self.date: - self.date = Date() + self.date = Date.Date() return self.date def set_date_object(self,date): @@ -1355,9 +1357,12 @@ class LdsOrd(SourceNote): def __init__(self,source=None): """Creates a LDS Ordinance instance""" SourceNote.__init__(self,source) + self.dp = DateHandler.create_parser() + self.dd = DateHandler.create_display() + if source: self.famc = source.famc - self.date = Date(source.date) + self.date = Date.Date(source.date) self.temple = source.temple self.status = source.status self.place = source.place @@ -1397,19 +1402,20 @@ class LdsOrd(SourceNote): def set_date(self, date) : """attempts to sets the date of the ordinance""" if not self.date: - self.date = Date() - self.date.set(date) + self.date = Date.Date() + self.dp.set_date(self.date,date) def get_date(self) : """returns a string representation of the date of the ordinance""" if self.date: - return self.date.get_date() - return "" + print self.dd + return self.dd.display(self.date) + return u"" def get_date_object(self): """returns the Date object associated with the ordinance""" if not self.date: - self.date = Date() + self.date = Date.Date() return self.date def set_date_object(self,date): @@ -1443,7 +1449,7 @@ class LdsOrd(SourceNote): self.place != other.place or self.status != other.status or self.temple != other.temple or - compare_dates(self.get_date_object(),other.get_date_object()) or + self.get_date_object() != other.get_date_object() or len(self.get_source_references()) != len(other.get_source_references())): return 0 @@ -1724,7 +1730,7 @@ class Address(DataObj): self.state = source.state self.country = source.country self.postal = source.postal - self.date = Date(source.date) + self.date = Date.Date(source.date) self.phone = source.phone else: self.street = "" @@ -1732,7 +1738,7 @@ class Address(DataObj): self.state = "" self.country = "" self.postal = "" - self.date = Date() + self.date = Date.Date() self.phone = "" def set_date(self,text): @@ -2073,14 +2079,14 @@ class SourceRef: self.confidence = source.confidence self.ref = source.ref self.page = source.page - self.date = Date(source.date) + self.date = Date.Date(source.date) self.comments = Note(source.comments.get()) self.text = source.text else: self.confidence = CONF_NORMAL self.ref = None self.page = "" - self.date = Date() + self.date = Date.Date() self.comments = Note() self.text = "" @@ -2141,7 +2147,7 @@ class SourceRef: if self.ref and other.ref: if self.page != other.page: return 0 - if compare_dates(self.date,other.date) != 0: + if self.date != other.date: return 0 if self.get_text() != other.get_text(): return 0 diff --git a/src/Sort.py b/src/Sort.py index ed0ecc29d..1a07fca02 100644 --- a/src/Sort.py +++ b/src/Sort.py @@ -62,16 +62,7 @@ def build_sort_date(n): use as a sort key in a GtkCList. The resultant string is in the format of YYYYMMDD. Unknown values are given as all nines, so that the appear at the end""" - y = n.start.year - if y < 0: - y = 9999 - m = n.start.month - if m < 0: - m = 99 - d = n.start.day - if d < 0: - d = 99 - return "%04d%02d%02d" % (y,m,d) + return "%010d" % n.get_sort_value() class Sort: def __init__(self,database): diff --git a/src/StartupDialog.py b/src/StartupDialog.py index 502d81cc7..f194ce476 100644 --- a/src/StartupDialog.py +++ b/src/StartupDialog.py @@ -237,13 +237,6 @@ class StartupDialog: box.add(align) vbox = gtk.VBox() vbox.set_spacing(6) - - self.calendar = gtk.CheckButton(label=_("Enable support for alternate calendars")) - - self.calendar.set_active(GrampsCfg.get_calendar()) - - align.add(self.calendar) - box.show_all() return p diff --git a/src/WriteGedcom.py b/src/WriteGedcom.py index 8918d1a02..3f5ae3c91 100644 --- a/src/WriteGedcom.py +++ b/src/WriteGedcom.py @@ -50,10 +50,6 @@ import GenericFilter import const import Utils import Date -import Calendar -import Julian -import Hebrew -import FrenchRepublic import GedcomInfo import Errors import ansel_utf8 @@ -87,15 +83,15 @@ _month = [ "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" ] _calmap = { - Hebrew.Hebrew.NAME : (_hmonth, '@#HEBREW@'), - FrenchRepublic.FrenchRepublic.NAME : (_fmonth, '@#FRENCH R@'), - Julian.Julian.NAME : (_month, '@#JULIAN@'), + Date.CAL_HEBREW : (_hmonth, '@#HEBREW@'), + Date.CAL_FRENCH : (_fmonth, '@#FRENCH R@'), + Date.CAL_JULIAN : (_month, '@#JULIAN@'), } _caldef = { - Calendar.ABOUT : "ABT", - Calendar.BEFORE : "BEF", - Calendar.AFTER : "AFT", + Date.MOD_ABOUT : "ABT", + Date.MOD_BEFORE : "BEF", + Date.MOD_AFTER : "AFT", } #------------------------------------------------------------------------- @@ -222,39 +218,29 @@ def sort_by_gramps_id(first,second): # # #------------------------------------------------------------------------- -def make_date(subdate): +def make_date(subdate,calendar,mode): retval = "" - day = subdate.get_day() - mon = subdate.get_month() - year = subdate.get_year() - mode = subdate.get_mode_val() - day_valid = subdate.get_day_valid() - mon_valid = subdate.get_month_valid() - year_valid = subdate.get_year_valid() + (day,mon,year,sl) = subdate - if _calmap.has_key(subdate.calendar.NAME): - (mmap,prefix) = _calmap[subdate.calendar.NAME] - else: - mmap = _month - prefix = "" + (mmap,prefix) = _calmap.get(calendar,(_month,"")) - if not day_valid: + if day == 0: try: - if not mon_valid: + if mon == 0: retval = '%d' % year - elif not year_valid: + elif year == 0: retval = '(%s)' % mmap[mon] else: retval = "%s %d" % (mmap[mon],year) except IndexError: print "Month index error - %d" % mon retval = '%d' % year - elif not mon_valid: + elif mon == 0: retval = '%d' % year else: try: month = mmap[mon] - if not year_valid: + if year == 0: retval = "(%d %s)" % (day,month) else: retval = "%d %s %d" % (day,month,year) @@ -285,63 +271,6 @@ def fmtline(text,limit,level,endl): app = "%s%d CONC " % (endl,level+1) return string.join(new_text,app) -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -def gedcom_date(date): - if date.range == 1: - s1 = ged_subdate(date.get_start_date()) - s2 = ged_subdate(date.get_stop_date()) - return "BET %s AND %s" % (s1,s2) - elif date.range == -1: - return "(%s)" % date.text - else: - return ged_subdate(date.start) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -def ged_subdate(date): - if not date.getValid(): - return "" - elif not date.getDayValid(): - try: - if not date.getMonthValid(): - retval = str(date.year) - elif not date.getYearValid(): - retval = "(%s)" % Date.SingleDate.emname[date.month] - else: - retval = "%s %d" % (Date.SingleDate.emname[date.month],date.year) - except IndexError: - print "Month index error - %d" % date.month - retval = str(date.year) - elif not date.getMonthValid(): - retval = str(date.year) - else: - try: - month = Date.SingleDate.emname[date.month] - if not date.getYearValid(): - retval = "(%d %s)" % (date.day,month) - else: - retval = "%d %s %d" % (date.day,month,date.year) - except IndexError: - print "Month index error - %d" % date.month - retval = str(date.year) - - if date.mode == Date.SingleDate.about: - retval = "ABT %s" % retval - - if date.mode == Date.SingleDate.before: - retval = "BEF %s" % retval - elif date.mode == Date.SingleDate.after: - retval = "AFT %s" % retval - - return retval - #------------------------------------------------------------------------- # # @@ -1191,11 +1120,16 @@ class GedcomWriter: if val: self.writeln("%s %s" % (prefix,self.cnvtxt(val))) elif not date.is_empty (): - if date.is_range(): - val = "FROM %s TO %s" % (make_date(start), - make_date(date.get_stop_date())) + cal = date.get_calendar() + mod = date.get_modifier() + if date.get_modifier() == Date.MOD_SPAN: + val = "FROM %s TO %s" % (make_date(start,cal,mod), + make_date(date.get_stop_date(),cal,mod)) + elif date.get_modifier() == Date.MOD_RANGE: + val = "BET %s AND %s" % (make_date(start,cal,mod), + make_date(date.get_stop_date(),cal,mod)) else: - val = make_date(start) + val = make_date(start,cal,mod) self.writeln("%s %s" % (prefix,val)) def write_person_name(self,name,nick): diff --git a/src/WriteXML.py b/src/WriteXML.py index cba3ddaad..9f38b40af 100644 --- a/src/WriteXML.py +++ b/src/WriteXML.py @@ -49,9 +49,10 @@ import gtk # #------------------------------------------------------------------------- import const -import Calendar import Gregorian import RelLib +import Date + from gettext import gettext as _ from QuestionDialog import ErrorDialog @@ -590,31 +591,48 @@ class XmlWriter: if value: self.g.write('%s<%s>%s\n' % (' '*indent,label,self.fix(value),label)) + def get_iso_date(self,date): + if date[2] == 0: + y = "????" + else: + y = "%04d" % date[2] + + if date[1] == 0: + if date[0] == 0: + m = "" + else: + m = "-??" + else: + m = "-%02d" % (date[1]) + if date[0] == 0: + d = '' + else: + d = "-%02d" % date[0] + return "%s%s%s" % (y,m,d) + def write_date(self,date,indent=1): sp = ' '*indent - if date.is_empty(): - return - name = date.get_calendar().NAME - if name != Gregorian.Gregorian.NAME: - calstr = ' cformat="%s"' % name + cal= date.get_calendar() + if cal != Date.CAL_GREGORIAN: + calstr = ' cformat="%s"' % Date.Date.calendar_names[cal] else: calstr = '' - if date.is_range(): - d1 = date.get_start_date().get_iso_date() - d2 = date.get_stop_date().get_iso_date() + mode = date.get_modifier() + + if date.is_compound(): + d1 = self.get_iso_date(date.get_start_date()) + d2 = self.get_iso_date(date.get_stop_date()) self.g.write('%s\n' % (sp,d1,d2,calstr)) - elif date.is_valid(): - d1 = date.get_start_date() - mode = d1.get_mode_val() - dstr = d1.get_iso_date() + elif mode != Date.MOD_TEXTONLY: + dstr = self.get_iso_date(date.get_start_date()) - if mode == Calendar.BEFORE: + if mode == Date.MOD_BEFORE: pref = ' type="before"' - elif mode == Calendar.AFTER: + elif mode == Date.MOD_AFTER: pref = ' type="after"' - elif mode == Calendar.ABOUT: + elif mode == Date.MOD_ABOUT: pref = ' type="about"' else: pref = "" diff --git a/src/calendars/Islamic.py b/src/calendars/Islamic.py deleted file mode 100644 index 705f0c551..000000000 --- a/src/calendars/Islamic.py +++ /dev/null @@ -1,101 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001 Donald N. Allingham -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -""" -Gregorian calendar module for GRAMPS. - -The original algorithms for this module came from Scott E. Lee's -C implementation. The original C source can be found at Scott's -web site at http://www.scottlee.com -""" - -__author__ = "Donald N. Allingham" -__version__ = "$Revision$" - -#------------------------------------------------------------------------- -# -# python modules -# -#------------------------------------------------------------------------- -import math - -#------------------------------------------------------------------------- -# -# Gramps Modules -# -#------------------------------------------------------------------------- -import Calendar -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# Islamic -# -#------------------------------------------------------------------------- -class Islamic(Calendar.Calendar): - """Islamic calendar""" - - EPOCH = 1948439.5 - - MONTHS = [ - "Muharram", "Safar", "Rabi`al-Awwal", "Rabi`ath-Thani", - "Jumada l-Ula", "Jumada t-Tania", "Rajab", "Sha`ban", - "Ramadan", "Shawwal", "Dhu l-Qa`da", "Dhu l-Hijja" - ] - - M2NUM = { - "muharram" : 1, "safar" : 2, "rabi`al-awwal" : 3, - "rabi`ath-thani" : 4, "jumada l-ula" : 5 , "jumada t-tania" : 6, - "rajab" : 7, "sha`ban" : 8, "ramadan" : 9, - "shawwal" : 10, "dhu l-qa`da" : 11, "dhu l-hijja" : 12 - } - - NAME = "Islamic" - TNAME = _("Islamic") - - def quote_display(self,year,month,day,mode): - return "%s (%s)" % (self.display(year,month,day,mode),Islamic.NAME) - - def set_month_string(self,text): - try: - return Islamic.M2NUM[unicode(text.lower())] - except KeyError: - return Calendar.UNDEF - - def month(self,val): - try: - return Islamic.MONTHS[val-1] - except: - return "Illegal Month" - - def get_sdn(self,year, month, day): - v1 = math.ceil(29.5 * (month - 1)) - v2 = (year - 1) * 354 - v3 = math.floor((3 + (11 *year)) / 30) - - return int(math.ceil((day + v1 + v2 + v3 + Islamic.EPOCH) - 1)) - - def get_ymd(self,sdn): - sdn = math.floor(sdn) + 0.5 - year = int(math.floor(((30*(sdn-Islamic.EPOCH))+10646)/10631)) - month = int(min(12, math.ceil((sdn-(29+self.get_sdn(year,1,1)))/29.5) + 1)) - day = int((sdn - self.get_sdn(year,month,1)) + 1) - return (year,month,day) - -Calendar.register(Islamic) diff --git a/src/calendars/Makefile.am b/src/calendars/Makefile.am deleted file mode 100644 index 9e11ed935..000000000 --- a/src/calendars/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -# This is the src/calendars level Makefile for Gramps -# Use GNU make's ':=' syntax for nice wildcard use. -# If not using GNU make, then list all .py files individually - -calendardir = $(datadir)/@PACKAGE@/calendars - -calendar_PYTHON = \ - Islamic.py \ - Persian.py - - -GRAMPS_PY_MODPATH = "../" - -pycheck: - (export PYTHONPATH=$(GRAMPS_PY_MODPATH); \ - pychecker $(pkgpython_PYTHON)); diff --git a/src/calendars/Persian.py b/src/calendars/Persian.py deleted file mode 100644 index 309d08fb8..000000000 --- a/src/calendars/Persian.py +++ /dev/null @@ -1,128 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001 Donald N. Allingham -# -# This program 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 2 of the License, or -# (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -""" -Gregorian calendar module for GRAMPS. - -The original algorithms for this module came from Scott E. Lee's -C implementation. The original C source can be found at Scott's -web site at http://www.scottlee.com -""" - -__author__ = "Donald N. Allingham" -__version__ = "$Revision$" - -#------------------------------------------------------------------------- -# -# python modules -# -#------------------------------------------------------------------------- -import math - -#------------------------------------------------------------------------- -# -# Gramps Modules -# -#------------------------------------------------------------------------- -import Calendar -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# Persian -# -#------------------------------------------------------------------------- -class Persian(Calendar.Calendar): - """Persian Calendar""" - - EPOCH = 1948320.5 - SDN_475_1_1 = 2121446 - - MONTHS = [ "Farvardin", "Ordibehesht", "Khordad", "Tir", "Mordad", - "Shahrivar", "Mehr", "Aban", "Azar", "Dey", "Bahman", "Esfand" ] - - M2NUM = { - "farvardin" : 1, "ordibehesht" : 2, "khordad" : 3, - "tir" : 4, "mordad" : 5, "shahrivar" : 6, - "mehr" : 7, "aban" : 8, "azar" : 9, - "dey" : 10, "bahman" : 11, "esfand" : 12 - } - - NAME = "Persian" - TNAME = _("Persian") - - def quote_display(self,year,month,day,mode): - return "%s (%s)" % (self.display(year,month,day,mode),Persian.NAME) - - def set_month_string(self,text): - try: - return Persian.M2NUM[unicode(text.lower())] - except KeyError: - return Calendar.UNDEF - - def month(self,val): - try: - return Persian.MONTHS[val-1] - except: - return "Illegal Month" - - def get_sdn(self,year, month, day): - if year >= 0: - epbase = year - 474 - else: - epbase = year - 473 - - epyear = 474 + epbase % 2820 - - if month <= 7: - v1 = (month - 1) * 31 - else: - v1 = ((month - 1) * 30) + 6 - v2 = math.floor(((epyear * 682) - 110) / 2816) - v3 = (epyear - 1) * 365 + day - v4 = math.floor(epbase / 2820) * 1029983 - - return int(math.ceil(v1 + v2 + v3 + v4 + Persian.EPOCH - 1)) - - def get_ymd(self,sdn): - sdn = math.floor(sdn) + 0.5 - - depoch = sdn - self.get_sdn(475,1,1) - cycle = math.floor(depoch / 1029983) - cyear = depoch % 1029983 - if cyear == 1029982: - ycycle = 2820 - else: - aux1 = math.floor(cyear / 366) - aux2 = cyear % 366 - ycycle = math.floor(((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) + aux1 + 1; - - year = ycycle + (2820 * cycle) + 474 - if year <= 0: - year = year - 1; - - yday = sdn - self.get_sdn(year, 1, 1) + 1 - if yday < 186: - month = math.ceil(yday / 31) - else: - month = math.ceil((yday - 6) / 30) - day = (sdn - self.get_sdn(year, month, 1)) + 1 - return (int(year), int(month), int(day)) - -Calendar.register(Persian) diff --git a/src/gramps.glade b/src/gramps.glade index f7ab44848..ded93dbe4 100644 --- a/src/gramps.glade +++ b/src/gramps.glade @@ -17379,74 +17379,6 @@ Other - - - True - True - 0 - - - - - - - - True - Icons Only - True - - - - - - True - Text Only - True - - - - - - True - Text Below Icons - True - - - - - - True - Text Beside Icons - True - - - - - - True - - - - - - True - GNOME Settings - True - - - - - - - 1 - 3 - 1 - 2 - fill - - - - True @@ -17516,6 +17448,74 @@ Other + + + + True + True + 0 + + + + + + + + True + Icons Only + True + + + + + + True + Text Only + True + + + + + + True + Text Below Icons + True + + + + + + True + Text Beside Icons + True + + + + + + True + + + + + + True + GNOME Settings + True + + + + + + + 1 + 2 + 1 + 2 + fill + + + 0 @@ -17780,6 +17780,7 @@ Other + 3 True True _Display Tip of the Day @@ -17842,7 +17843,7 @@ Other 12 True - 7 + 4 3 False 6 @@ -17920,76 +17921,6 @@ Other - - - True - D_ate format: - True - False - GTK_JUSTIFY_CENTER - False - False - 0 - 0.5 - 5 - 5 - date_entry_format - - - 1 - 2 - 4 - 5 - fill - - - - - - - True - True - -1 - - - - True - - - - - 2 - 3 - 4 - 5 - fill - - - - - - - True - True - _Show calendar format selection menu - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - 1 - 3 - 6 - 7 - fill - - - - True @@ -18014,54 +17945,6 @@ Other - - - True - <b>Entry formats</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 0 - 3 - 3 - 4 - fill - - - - - - - True - <b>Calendars</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - 0 - 3 - 5 - 6 - fill - - - - True @@ -18079,6 +17962,7 @@ Other 3 1 2 + fill @@ -18907,7 +18791,7 @@ Other 12 True 6 - 3 + 2 False 6 12 @@ -19021,7 +18905,7 @@ Other 0 - 3 + 2 0 1 fill @@ -19045,7 +18929,7 @@ Other 0 - 3 + 2 4 5 fill @@ -19088,7 +18972,7 @@ Other 12 True - 8 + 7 3 False 6 diff --git a/src/gramps_main.py b/src/gramps_main.py index 5e0978345..35dab6057 100755 --- a/src/gramps_main.py +++ b/src/gramps_main.py @@ -73,6 +73,7 @@ import DbPrompter import TipOfDay import ArgHandler import Exporter +import DateDisplay from QuestionDialog import * @@ -140,7 +141,6 @@ class Gramps: "family database to this development version. This version may " "contain bugs which could corrupt your database.")) GrampsCfg.save_betawarn(1) - self.RelClass = Plugins.relationship_class self.relationship = self.RelClass(self.db)