diff --git a/src/DateEdit.py b/src/DateEdit.py
index d05bd861d..c6a289c23 100644
--- a/src/DateEdit.py
+++ b/src/DateEdit.py
@@ -2,6 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2002-2006 Donald N. Allingham
+# Copyright (C) 2009 Douglas S. Blank
#
# 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
@@ -248,10 +249,22 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
self.start_year.set_sensitive(0)
self.calendar_box.set_sensitive(0)
self.quality_box.set_sensitive(0)
+ self.dual_dated.set_sensitive(0)
+ self.new_year.set_sensitive(0)
self.text_entry = self.top.get_widget('date_text_entry')
self.text_entry.set_text(self.date.get_text())
-
+
+ self.dual_dated = self.top.get_widget('dualdated')
+ if self.date.get_slash():
+ self.dual_dated.set_active(1)
+ self.calendar_box.set_sensitive(0)
+ self.calendar_box.set_active(Date.CAL_JULIAN)
+ self.dual_dated.connect('toggled', self.switch_dual_dated)
+
+ self.new_year = self.top.get_widget('newyear')
+ self.new_year.set_active(self.date.get_new_year())
+
# The dialog is modal -- since dates don't have names, we don't
# want to have several open dialogs, since then the user will
# loose track of which is which. Much like opening files.
@@ -270,14 +283,15 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
else:
if response == gtk.RESPONSE_OK:
(the_quality, the_modifier, the_calendar,
- the_value, the_text) = self.build_date_from_ui()
+ the_value, the_text, the_newyear) = self.build_date_from_ui()
self.return_date = Date(self.date)
self.return_date.set(
quality=the_quality,
modifier=the_modifier,
calendar=the_calendar,
value=the_value,
- text=the_text)
+ text=the_text,
+ newyear=the_newyear)
self.close()
break
@@ -313,19 +327,20 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
self.start_day.get_value_as_int(),
self.start_month_box.get_active(),
self.start_year.get_value_as_int(),
- False,
+ self.dual_dated.get_active(),
self.stop_day.get_value_as_int(),
self.stop_month_box.get_active(),
self.stop_year.get_value_as_int(),
- False)
+ self.dual_dated.get_active())
else:
value = (
self.start_day.get_value_as_int(),
self.start_month_box.get_active(),
self.start_year.get_value_as_int(),
- False)
+ self.dual_dated.get_active())
calendar = self.calendar_box.get_active()
- return (quality, modifier, calendar, value, text)
+ newyear = self.new_year.get_active()
+ return (quality, modifier, calendar, value, text, newyear)
def switch_type(self, obj):
"""
@@ -352,6 +367,20 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
self.start_year.set_sensitive(date_sensitivity)
self.calendar_box.set_sensitive(date_sensitivity)
self.quality_box.set_sensitive(date_sensitivity)
+ self.dual_dated.set_sensitive(date_sensitivity)
+ self.new_year.set_sensitive(date_sensitivity)
+
+ def switch_dual_dated(self, obj):
+ """
+ Changed whether this is a dual dated year, or not.
+ Dual dated years are represented in the Julian calendar
+ so that the day/months don't changed in the Text representation.
+ """
+ if self.dual_dated.get_active():
+ self.calendar_box.set_active(Date.CAL_JULIAN)
+ self.calendar_box.set_sensitive(0)
+ else:
+ self.calendar_box.set_sensitive(1)
def switch_calendar(self, obj):
"""
@@ -362,14 +391,15 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
old_cal = self.date.get_calendar()
new_cal = self.calendar_box.get_active()
- (the_quality, the_modifier, the_calendar, the_value, the_text) = \
- self.build_date_from_ui()
+ (the_quality, the_modifier, the_calendar,
+ the_value, the_text, the_newyear) = self.build_date_from_ui()
self.date.set(
quality=the_quality,
modifier=the_modifier,
calendar=old_cal,
value=the_value,
- text=the_text)
+ text=the_text,
+ newyear=the_newyear)
if not self.date.is_empty():
self.date.convert_calendar(new_cal)
diff --git a/src/DateHandler/_DateDisplay.py b/src/DateHandler/_DateDisplay.py
index 0150ef430..a47a66416 100644
--- a/src/DateHandler/_DateDisplay.py
+++ b/src/DateHandler/_DateDisplay.py
@@ -91,9 +91,11 @@ class DateDisplay:
formats = ("YYYY-MM-DD (ISO)", )
calendar = (
- "", " (Julian)", " (Hebrew)", " (French Republican)",
- " (Persian)", " (Islamic)"
+ "", "Julian", "Hebrew", "French Republican",
+ "Persian", "Islamic"
)
+
+ newyear = ("", "Mar1", "Mar25", "Sep1")
_mod_str = ("", "before ", "after ", "about ", "", "", "")
@@ -133,6 +135,22 @@ class DateDisplay:
else:
return self.display(date)
+ def format_extras(self, cal, newyear):
+ """
+ Formats the extra items (calendar, newyear) for a date.
+ """
+ scal = self.calendar[cal]
+ snewyear = self.newyear[newyear]
+ retval = ""
+ for item in [scal, snewyear]:
+ if item:
+ if retval:
+ retval += ","
+ retval += item
+ if retval:
+ return " (%s)" % retval
+ return ""
+
def display(self, date):
"""
Return a text string representing the date.
@@ -141,6 +159,7 @@ class DateDisplay:
cal = date.get_calendar()
qual = date.get_quality()
start = date.get_start_date()
+ newyear = date.get_new_year()
qual_str = self._qual_str[qual]
@@ -151,11 +170,12 @@ class DateDisplay:
elif mod == Date.MOD_SPAN or mod == Date.MOD_RANGE:
d1 = self.display_iso(start)
d2 = self.display_iso(date.get_stop_date())
- return "%s %s - %s%s" % (qual_str, d1, d2, self.calendar[cal])
+ scal = self.format_extras(cal, newyear)
+ return "%s %s - %s%s" % (qual_str, d1, d2, scal)
else:
text = self.display_iso(start)
- return "%s%s%s%s" % (qual_str, self._mod_str[mod], text,
- self.calendar[cal])
+ scal = self.format_extras(cal, newyear)
+ return "%s%s%s%s" % (qual_str, self._mod_str[mod], text, scal)
def _slash_year(self, val, slash):
if val < 0:
@@ -328,6 +348,7 @@ class DateDisplayEn(DateDisplay):
cal = date.get_calendar()
qual = date.get_quality()
start = date.get_start_date()
+ newyear = date.get_new_year()
qual_str = self._qual_str[qual]
@@ -338,13 +359,14 @@ class DateDisplayEn(DateDisplay):
elif mod == Date.MOD_SPAN:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date())
- return "%sfrom %s to %s%s" % (qual_str, d1, d2, self.calendar[cal])
+ scal = self.format_extras(cal, newyear)
+ return "%sfrom %s to %s%s" % (qual_str, d1, d2, scal)
elif mod == Date.MOD_RANGE:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date())
- return "%sbetween %s and %s%s" % (qual_str, d1, d2,
- self.calendar[cal])
+ scal = self.format_extras(cal, newyear)
+ return "%sbetween %s and %s%s" % (qual_str, d1, d2, scal)
else:
text = self.display_cal[date.get_calendar()](start)
- return "%s%s%s%s" % (qual_str, self._mod_str[mod],
- text, self.calendar[cal])
+ scal = self.format_extras(cal, newyear)
+ return "%s%s%s%s" % (qual_str, self._mod_str[mod], text, scal)
diff --git a/src/DateHandler/_DateParser.py b/src/DateHandler/_DateParser.py
index 04970ce34..99f32906d 100644
--- a/src/DateHandler/_DateParser.py
+++ b/src/DateHandler/_DateParser.py
@@ -173,6 +173,12 @@ class DateParser:
'persian' : Date.CAL_PERSIAN,
'p' : Date.CAL_PERSIAN,
}
+
+ newyear_to_int = {
+ "mar1": Date.NEWYEAR_MAR1,
+ "mar25": Date.NEWYEAR_MAR25,
+ "sep1" : Date.NEWYEAR_SEP1,
+ }
quality_to_int = {
'estimated' : Date.QUAL_ESTIMATED,
@@ -240,6 +246,7 @@ class DateParser:
self._pmon_str = self.re_longest_first(self.persian_to_int.keys())
self._imon_str = self.re_longest_first(self.islamic_to_int.keys())
self._cal_str = self.re_longest_first(self.calendar_to_int.keys())
+ self._ny_str = self.re_longest_first(self.newyear_to_int.keys())
# bce, calendar type and quality may be either at the end or at
# the beginning of the given date string, therefore they will
@@ -248,6 +255,11 @@ class DateParser:
self._cal = re.compile("(.*)\s+\(%s\)( ?.*)" % self._cal_str,
re.IGNORECASE)
+ self._calny = re.compile("(.*)\s+\(%s,%s\)( ?.*)" % (self._cal_str,
+ self._ny_str),
+ re.IGNORECASE)
+ self._ny = re.compile("(.*)\s+\(%s\)( ?.*)" % self._ny_str,
+ re.IGNORECASE)
self._qual = re.compile("(.* ?)%s\s+(.+)" % self._qual_str,
re.IGNORECASE)
@@ -448,6 +460,31 @@ class DateParser:
text = match.group(1) + match.group(3)
return (text, cal)
+ def match_calendar_newyear(self, text, cal, newyear):
+ """
+ Try parsing calendar and newyear code.
+
+ Return newyear index and the text with calendar removed.
+ """
+ match = self._calny.match(text)
+ if match:
+ cal = self.calendar_to_int[match.group(2).lower()]
+ newyear = self.newyear_to_int[match.group(3).lower()]
+ text = match.group(1) + match.group(4)
+ return (text, cal, newyear)
+
+ def match_newyear(self, text, newyear):
+ """
+ Try parsing calendar and newyear code.
+
+ Return newyear index and the text with calendar removed.
+ """
+ match = self._ny.match(text)
+ if match:
+ newyear = self.newyear_to_int[match.group(2).lower()]
+ text = match.group(1) + match.group(3)
+ return (text, newyear)
+
def match_quality(self, text, qual):
"""
Try matching quality.
@@ -460,7 +497,7 @@ class DateParser:
text = match.group(1) + match.group(3)
return (text, qual)
- def match_span(self, text, cal, qual, date):
+ def match_span(self, text, cal, ny, qual, date):
"""
Try matching span date.
@@ -479,11 +516,11 @@ class DateParser:
if bc2:
stop = self.invert_year(stop)
- date.set(qual, Date.MOD_SPAN, cal, start + stop)
+ date.set(qual, Date.MOD_SPAN, cal, start + stop, newyear=ny)
return 1
return 0
- def match_range(self, text, cal, qual, date):
+ def match_range(self, text, cal, ny, qual, date):
"""
Try matching range date.
@@ -502,7 +539,7 @@ class DateParser:
if bc2:
stop = self.invert_year(stop)
- date.set(qual, Date.MOD_RANGE, cal, start + stop)
+ date.set(qual, Date.MOD_RANGE, cal, start + stop, newyear=ny)
return 1
return 0
@@ -523,7 +560,7 @@ class DateParser:
bc = True
return (text, bc)
- def match_modifier(self, text, cal, qual, bc, date):
+ def match_modifier(self, text, cal, ny, qual, bc, date):
"""
Try matching date with modifier.
@@ -539,9 +576,9 @@ class DateParser:
date.set_modifier(Date.MOD_TEXTONLY)
date.set_text_value(text)
elif bc:
- date.set(qual, mod, cal, self.invert_year(start))
+ date.set(qual, mod, cal, self.invert_year(start), newyear=ny)
else:
- date.set(qual, mod, cal, start)
+ date.set(qual, mod, cal, start, newyear=ny)
return True
# modifiers after the date
if self.modifier_after_to_int:
@@ -552,9 +589,9 @@ class DateParser:
mod = self.modifier_after_to_int.get(grps[1].lower(),
Date.MOD_NONE)
if bc:
- date.set(qual, mod, cal, self.invert_year(start))
+ date.set(qual, mod, cal, self.invert_year(start), newyear=ny)
else:
- date.set(qual, mod, cal, start)
+ date.set(qual, mod, cal, start, newyear=ny)
return True
match = self._abt2.match(text)
if match:
@@ -562,9 +599,9 @@ class DateParser:
start = self._parse_subdate(grps[0])
mod = Date.MOD_ABOUT
if bc:
- date.set(qual, mod, cal, self.invert_year(start))
+ date.set(qual, mod, cal, self.invert_year(start), newyear=ny)
else:
- date.set(qual, mod, cal, start)
+ date.set(qual, mod, cal, start, newyear=ny)
return True
return False
@@ -576,17 +613,20 @@ class DateParser:
date.set_text_value(text)
qual = Date.QUAL_NONE
cal = Date.CAL_GREGORIAN
+ newyear = Date.NEWYEAR_JAN1
+ (text, cal, newyear) = self.match_calendar_newyear(text, cal, newyear)
(text, cal) = self.match_calendar(text, cal)
+ (text, newyear) = self.match_newyear(text, newyear)
(text, qual) = self.match_quality(text, qual)
- if self.match_span(text, cal, qual, date):
+ if self.match_span(text, cal, newyear, qual, date):
return
- if self.match_range(text, cal, qual, date):
+ if self.match_range(text, cal, newyear, qual, date):
return
(text, bc) = self.match_bce(text)
- if self.match_modifier(text, cal, qual, bc, date):
+ if self.match_modifier(text, cal, newyear, qual, bc, date):
return
try:
@@ -599,13 +639,9 @@ class DateParser:
return
if bc:
- date.set(qual, Date.MOD_NONE, cal, self.invert_year(subdate))
+ date.set(qual, Date.MOD_NONE, cal, self.invert_year(subdate), newyear=newyear)
else:
- date.set(qual, Date.MOD_NONE, cal, subdate)
-
- if date.get_slash():
- date.set_calendar(Date.CAL_JULIAN)
- date.recalc_sort_value() # needed after the calendar change
+ date.set(qual, Date.MOD_NONE, cal, subdate, newyear=newyear)
def invert_year(self, subdate):
return (subdate[0], subdate[1], -subdate[2], subdate[3])
diff --git a/src/gen/lib/date.py b/src/gen/lib/date.py
index 16334c8a5..9d6fae82b 100644
--- a/src/gen/lib/date.py
+++ b/src/gen/lib/date.py
@@ -259,6 +259,9 @@ class Span:
def is_valid(self):
return self.valid
+ def tuple(self):
+ return self._diff(self.date1, self.date2)
+
def __getitem__(self, pos):
# Depricated!
return self._diff(self.date1, self.date2)[pos]
@@ -664,6 +667,8 @@ class Date:
if isinstance(source, tuple):
if calendar is None:
self.calendar = Date.CAL_GREGORIAN
+ elif isinstance(calendar, int):
+ self.calendar = calendar
else:
self.calendar = self.lookup_calendar(calendar)
if modifier is None:
@@ -1165,6 +1170,18 @@ class Date:
"""
return self._get_low_item(Date._POS_YR)
+ def get_new_year(self):
+ """
+ Return the new year code associated with the date.
+ """
+ return self.newyear
+
+ def set_new_year(self, value):
+ """
+ Set the new year code associated with the date.
+ """
+ self.newyear = value
+
def set_yr_mon_day(self, year, month, day):
"""
Set the year, month, and day values.
@@ -1335,7 +1352,8 @@ class Date:
"""
return self.text
- def set(self, quality, modifier, calendar, value, text=None):
+ def set(self, quality, modifier, calendar, value, text=None,
+ newyear=0):
"""
Set the date to the specified value.
@@ -1379,14 +1397,38 @@ class Date:
self.modifier = modifier
self.calendar = calendar
self.dateval = value
+ self.set_new_year(newyear)
year = max(value[Date._POS_YR], 1)
month = max(value[Date._POS_MON], 1)
day = max(value[Date._POS_DAY], 1)
+
if year == month == 0 and day == 0:
self.sortval = 0
else:
func = Date._calendar_convert[calendar]
self.sortval = func(year, month, day)
+
+ if self.get_slash() and self.get_calendar() != Date.CAL_JULIAN:
+ self.set_calendar(Date.CAL_JULIAN)
+ self.recalc_sort_value()
+
+ ny = self.get_new_year()
+ if ny: # new year offset?
+ if ny == Date.NEWYEAR_MAR1:
+ split = (3, 1)
+ elif ny == Date.NEWYEAR_MAR25:
+ split = (3, 25)
+ elif ny == Date.NEWYEAR_SEP1:
+ split = (9, 1)
+ if (self.get_month(), self.get_day()) >= split:
+ d1 = Date(self.get_year(), 1, 1, calendar=self.calendar).sortval
+ d2 = Date(self.get_year(), split[0], split[1], calendar=self.calendar).sortval
+ self.sortval -= (d2 - d1)
+ else:
+ d1 = Date(self.get_year(), 12, 31, calendar=self.calendar).sortval
+ d2 = Date(self.get_year(), split[0], split[1], calendar=self.calendar).sortval
+ self.sortval += (d1 - d2) + 1
+
if text:
self.text = text
@@ -1551,10 +1593,16 @@ class Date:
def get_slash(self):
"""
- Return true if the date is a slash-date.
+ Return true if the date is a slash-date (dual dated).
"""
return self._get_low_item_valid(Date._POS_SL)
+ def set_slash(self, value):
+ """
+ Set to 1 if the date is a slash-date (dual dated).
+ """
+ self.dateval[Date._POS_SL] = value
+
def Today():
"""
Returns a Date object set to the current date.
diff --git a/src/glade/gramps.glade b/src/glade/gramps.glade
index 382b57a76..5f4e8cba7 100644
--- a/src/glade/gramps.glade
+++ b/src/glade/gramps.glade
@@ -9354,6 +9354,108 @@
+
+
+ True
+ False
+ 0
+
+
+
+ True
+
+ False
+ False
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 15
+ False
+ False
+
+
+
+
+
+ True
+ Old Style/New Style
+ True
+ Dua_l dated
+ True
+ GTK_RELIEF_NORMAL
+ True
+ False
+ False
+ True
+
+
+ 0
+ False
+ False
+
+
+
+
+
+ True
+ Ne_w year begins:
+ True
+ False
+ GTK_JUSTIFY_RIGHT
+ False
+ False
+ 1
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 0
+ True
+ True
+
+
+
+
+
+ True
+ January 1
+March 1
+March 25
+September 1
+
+ False
+ True
+
+
+
+ 0
+ True
+ True
+
+
+
+
+ 6
+ True
+ True
+
+
+
True
@@ -9813,8 +9915,8 @@
6
- True
- True
+ False
+ False
@@ -9870,9 +9972,9 @@
- 6
- False
- False
+ 0
+ True
+ True