Bug fix #1834, 1842: new-year boundaries in history, and editing slash dates: These changes allow the date editor dialog to change slashdates, and to change the first day of the year from Jan1. This is important for some date calculations and orderings. In order to do this, a new date format variation has been added. You can put Mar1, Mar25, or Sept1 in the parens with or without a Calendar type. For example: 'Jan 1, 1735 (Julian,Mar25)'. See further docs in wiki.

svn: r11644
This commit is contained in:
Doug Blank 2009-01-17 14:33:10 +00:00
parent 2170b850ee
commit ed35e1de38
5 changed files with 285 additions and 47 deletions

View File

@ -2,6 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
# Copyright (C) 2002-2006 Donald N. Allingham # 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 # 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 # 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.start_year.set_sensitive(0)
self.calendar_box.set_sensitive(0) self.calendar_box.set_sensitive(0)
self.quality_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 = self.top.get_widget('date_text_entry')
self.text_entry.set_text(self.date.get_text()) 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 # The dialog is modal -- since dates don't have names, we don't
# want to have several open dialogs, since then the user will # want to have several open dialogs, since then the user will
# loose track of which is which. Much like opening files. # loose track of which is which. Much like opening files.
@ -270,14 +283,15 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
else: else:
if response == gtk.RESPONSE_OK: if response == gtk.RESPONSE_OK:
(the_quality, the_modifier, the_calendar, (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 = Date(self.date)
self.return_date.set( self.return_date.set(
quality=the_quality, quality=the_quality,
modifier=the_modifier, modifier=the_modifier,
calendar=the_calendar, calendar=the_calendar,
value=the_value, value=the_value,
text=the_text) text=the_text,
newyear=the_newyear)
self.close() self.close()
break break
@ -313,19 +327,20 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
self.start_day.get_value_as_int(), self.start_day.get_value_as_int(),
self.start_month_box.get_active(), self.start_month_box.get_active(),
self.start_year.get_value_as_int(), self.start_year.get_value_as_int(),
False, self.dual_dated.get_active(),
self.stop_day.get_value_as_int(), self.stop_day.get_value_as_int(),
self.stop_month_box.get_active(), self.stop_month_box.get_active(),
self.stop_year.get_value_as_int(), self.stop_year.get_value_as_int(),
False) self.dual_dated.get_active())
else: else:
value = ( value = (
self.start_day.get_value_as_int(), self.start_day.get_value_as_int(),
self.start_month_box.get_active(), self.start_month_box.get_active(),
self.start_year.get_value_as_int(), self.start_year.get_value_as_int(),
False) self.dual_dated.get_active())
calendar = self.calendar_box.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): def switch_type(self, obj):
""" """
@ -352,6 +367,20 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
self.start_year.set_sensitive(date_sensitivity) self.start_year.set_sensitive(date_sensitivity)
self.calendar_box.set_sensitive(date_sensitivity) self.calendar_box.set_sensitive(date_sensitivity)
self.quality_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): def switch_calendar(self, obj):
""" """
@ -362,14 +391,15 @@ class DateEditorDialog(ManagedWindow.ManagedWindow):
old_cal = self.date.get_calendar() old_cal = self.date.get_calendar()
new_cal = self.calendar_box.get_active() new_cal = self.calendar_box.get_active()
(the_quality, the_modifier, the_calendar, the_value, the_text) = \ (the_quality, the_modifier, the_calendar,
self.build_date_from_ui() the_value, the_text, the_newyear) = self.build_date_from_ui()
self.date.set( self.date.set(
quality=the_quality, quality=the_quality,
modifier=the_modifier, modifier=the_modifier,
calendar=old_cal, calendar=old_cal,
value=the_value, value=the_value,
text=the_text) text=the_text,
newyear=the_newyear)
if not self.date.is_empty(): if not self.date.is_empty():
self.date.convert_calendar(new_cal) self.date.convert_calendar(new_cal)

View File

@ -91,9 +91,11 @@ class DateDisplay:
formats = ("YYYY-MM-DD (ISO)", ) formats = ("YYYY-MM-DD (ISO)", )
calendar = ( calendar = (
"", " (Julian)", " (Hebrew)", " (French Republican)", "", "Julian", "Hebrew", "French Republican",
" (Persian)", " (Islamic)" "Persian", "Islamic"
) )
newyear = ("", "Mar1", "Mar25", "Sep1")
_mod_str = ("", "before ", "after ", "about ", "", "", "") _mod_str = ("", "before ", "after ", "about ", "", "", "")
@ -133,6 +135,22 @@ class DateDisplay:
else: else:
return self.display(date) 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): def display(self, date):
""" """
Return a text string representing the date. Return a text string representing the date.
@ -141,6 +159,7 @@ class DateDisplay:
cal = date.get_calendar() cal = date.get_calendar()
qual = date.get_quality() qual = date.get_quality()
start = date.get_start_date() start = date.get_start_date()
newyear = date.get_new_year()
qual_str = self._qual_str[qual] qual_str = self._qual_str[qual]
@ -151,11 +170,12 @@ class DateDisplay:
elif mod == Date.MOD_SPAN or mod == Date.MOD_RANGE: elif mod == Date.MOD_SPAN or mod == Date.MOD_RANGE:
d1 = self.display_iso(start) d1 = self.display_iso(start)
d2 = self.display_iso(date.get_stop_date()) 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: else:
text = self.display_iso(start) text = self.display_iso(start)
return "%s%s%s%s" % (qual_str, self._mod_str[mod], text, scal = self.format_extras(cal, newyear)
self.calendar[cal]) return "%s%s%s%s" % (qual_str, self._mod_str[mod], text, scal)
def _slash_year(self, val, slash): def _slash_year(self, val, slash):
if val < 0: if val < 0:
@ -328,6 +348,7 @@ class DateDisplayEn(DateDisplay):
cal = date.get_calendar() cal = date.get_calendar()
qual = date.get_quality() qual = date.get_quality()
start = date.get_start_date() start = date.get_start_date()
newyear = date.get_new_year()
qual_str = self._qual_str[qual] qual_str = self._qual_str[qual]
@ -338,13 +359,14 @@ class DateDisplayEn(DateDisplay):
elif mod == Date.MOD_SPAN: elif mod == Date.MOD_SPAN:
d1 = self.display_cal[cal](start) d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date()) 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: elif mod == Date.MOD_RANGE:
d1 = self.display_cal[cal](start) d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date()) d2 = self.display_cal[cal](date.get_stop_date())
return "%sbetween %s and %s%s" % (qual_str, d1, d2, scal = self.format_extras(cal, newyear)
self.calendar[cal]) return "%sbetween %s and %s%s" % (qual_str, d1, d2, scal)
else: else:
text = self.display_cal[date.get_calendar()](start) text = self.display_cal[date.get_calendar()](start)
return "%s%s%s%s" % (qual_str, self._mod_str[mod], scal = self.format_extras(cal, newyear)
text, self.calendar[cal]) return "%s%s%s%s" % (qual_str, self._mod_str[mod], text, scal)

View File

@ -173,6 +173,12 @@ class DateParser:
'persian' : Date.CAL_PERSIAN, 'persian' : Date.CAL_PERSIAN,
'p' : 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 = { quality_to_int = {
'estimated' : Date.QUAL_ESTIMATED, 'estimated' : Date.QUAL_ESTIMATED,
@ -240,6 +246,7 @@ class DateParser:
self._pmon_str = self.re_longest_first(self.persian_to_int.keys()) 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._imon_str = self.re_longest_first(self.islamic_to_int.keys())
self._cal_str = self.re_longest_first(self.calendar_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 # bce, calendar type and quality may be either at the end or at
# the beginning of the given date string, therefore they will # 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, self._cal = re.compile("(.*)\s+\(%s\)( ?.*)" % self._cal_str,
re.IGNORECASE) 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, self._qual = re.compile("(.* ?)%s\s+(.+)" % self._qual_str,
re.IGNORECASE) re.IGNORECASE)
@ -448,6 +460,31 @@ class DateParser:
text = match.group(1) + match.group(3) text = match.group(1) + match.group(3)
return (text, cal) 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): def match_quality(self, text, qual):
""" """
Try matching quality. Try matching quality.
@ -460,7 +497,7 @@ class DateParser:
text = match.group(1) + match.group(3) text = match.group(1) + match.group(3)
return (text, qual) return (text, qual)
def match_span(self, text, cal, qual, date): def match_span(self, text, cal, ny, qual, date):
""" """
Try matching span date. Try matching span date.
@ -479,11 +516,11 @@ class DateParser:
if bc2: if bc2:
stop = self.invert_year(stop) 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 1
return 0 return 0
def match_range(self, text, cal, qual, date): def match_range(self, text, cal, ny, qual, date):
""" """
Try matching range date. Try matching range date.
@ -502,7 +539,7 @@ class DateParser:
if bc2: if bc2:
stop = self.invert_year(stop) 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 1
return 0 return 0
@ -523,7 +560,7 @@ class DateParser:
bc = True bc = True
return (text, bc) 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. Try matching date with modifier.
@ -539,9 +576,9 @@ class DateParser:
date.set_modifier(Date.MOD_TEXTONLY) date.set_modifier(Date.MOD_TEXTONLY)
date.set_text_value(text) date.set_text_value(text)
elif bc: elif bc:
date.set(qual, mod, cal, self.invert_year(start)) date.set(qual, mod, cal, self.invert_year(start), newyear=ny)
else: else:
date.set(qual, mod, cal, start) date.set(qual, mod, cal, start, newyear=ny)
return True return True
# modifiers after the date # modifiers after the date
if self.modifier_after_to_int: if self.modifier_after_to_int:
@ -552,9 +589,9 @@ class DateParser:
mod = self.modifier_after_to_int.get(grps[1].lower(), mod = self.modifier_after_to_int.get(grps[1].lower(),
Date.MOD_NONE) Date.MOD_NONE)
if bc: if bc:
date.set(qual, mod, cal, self.invert_year(start)) date.set(qual, mod, cal, self.invert_year(start), newyear=ny)
else: else:
date.set(qual, mod, cal, start) date.set(qual, mod, cal, start, newyear=ny)
return True return True
match = self._abt2.match(text) match = self._abt2.match(text)
if match: if match:
@ -562,9 +599,9 @@ class DateParser:
start = self._parse_subdate(grps[0]) start = self._parse_subdate(grps[0])
mod = Date.MOD_ABOUT mod = Date.MOD_ABOUT
if bc: if bc:
date.set(qual, mod, cal, self.invert_year(start)) date.set(qual, mod, cal, self.invert_year(start), newyear=ny)
else: else:
date.set(qual, mod, cal, start) date.set(qual, mod, cal, start, newyear=ny)
return True return True
return False return False
@ -576,17 +613,20 @@ class DateParser:
date.set_text_value(text) date.set_text_value(text)
qual = Date.QUAL_NONE qual = Date.QUAL_NONE
cal = Date.CAL_GREGORIAN 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, cal) = self.match_calendar(text, cal)
(text, newyear) = self.match_newyear(text, newyear)
(text, qual) = self.match_quality(text, qual) (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 return
if self.match_range(text, cal, qual, date): if self.match_range(text, cal, newyear, qual, date):
return return
(text, bc) = self.match_bce(text) (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 return
try: try:
@ -599,13 +639,9 @@ class DateParser:
return return
if bc: 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: else:
date.set(qual, Date.MOD_NONE, cal, subdate) date.set(qual, Date.MOD_NONE, cal, subdate, newyear=newyear)
if date.get_slash():
date.set_calendar(Date.CAL_JULIAN)
date.recalc_sort_value() # needed after the calendar change
def invert_year(self, subdate): def invert_year(self, subdate):
return (subdate[0], subdate[1], -subdate[2], subdate[3]) return (subdate[0], subdate[1], -subdate[2], subdate[3])

View File

@ -259,6 +259,9 @@ class Span:
def is_valid(self): def is_valid(self):
return self.valid return self.valid
def tuple(self):
return self._diff(self.date1, self.date2)
def __getitem__(self, pos): def __getitem__(self, pos):
# Depricated! # Depricated!
return self._diff(self.date1, self.date2)[pos] return self._diff(self.date1, self.date2)[pos]
@ -664,6 +667,8 @@ class Date:
if isinstance(source, tuple): if isinstance(source, tuple):
if calendar is None: if calendar is None:
self.calendar = Date.CAL_GREGORIAN self.calendar = Date.CAL_GREGORIAN
elif isinstance(calendar, int):
self.calendar = calendar
else: else:
self.calendar = self.lookup_calendar(calendar) self.calendar = self.lookup_calendar(calendar)
if modifier is None: if modifier is None:
@ -1165,6 +1170,18 @@ class Date:
""" """
return self._get_low_item(Date._POS_YR) 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): def set_yr_mon_day(self, year, month, day):
""" """
Set the year, month, and day values. Set the year, month, and day values.
@ -1335,7 +1352,8 @@ class Date:
""" """
return self.text 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. Set the date to the specified value.
@ -1379,14 +1397,38 @@ class Date:
self.modifier = modifier self.modifier = modifier
self.calendar = calendar self.calendar = calendar
self.dateval = value self.dateval = value
self.set_new_year(newyear)
year = max(value[Date._POS_YR], 1) year = max(value[Date._POS_YR], 1)
month = max(value[Date._POS_MON], 1) month = max(value[Date._POS_MON], 1)
day = max(value[Date._POS_DAY], 1) day = max(value[Date._POS_DAY], 1)
if year == month == 0 and day == 0: if year == month == 0 and day == 0:
self.sortval = 0 self.sortval = 0
else: else:
func = Date._calendar_convert[calendar] func = Date._calendar_convert[calendar]
self.sortval = func(year, month, day) 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: if text:
self.text = text self.text = text
@ -1551,10 +1593,16 @@ class Date:
def get_slash(self): 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) 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(): def Today():
""" """
Returns a Date object set to the current date. Returns a Date object set to the current date.

View File

@ -9354,6 +9354,108 @@
</packing> </packing>
</child> </child>
<child>
<widget class="GtkHBox" id="hbox145">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkLabel" id="label718">
<property name="visible">True</property>
<property name="label" translatable="yes"></property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">15</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="dualdated">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Old Style/New Style</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Dua_l dated</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label717">
<property name="visible">True</property>
<property name="label" translatable="yes">Ne_w year begins: </property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_RIGHT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">1</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="newyear">
<property name="visible">True</property>
<property name="items" translatable="yes">January 1
March 1
March 25
September 1
</property>
<property name="add_tearoffs">False</property>
<property name="focus_on_click">True</property>
<accelerator key="w" modifiers="GDK_MOD1_MASK" signal="grab_focus"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">6</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child> <child>
<widget class="GtkTable" id="table48"> <widget class="GtkTable" id="table48">
<property name="visible">True</property> <property name="visible">True</property>
@ -9813,8 +9915,8 @@
</widget> </widget>
<packing> <packing>
<property name="padding">6</property> <property name="padding">6</property>
<property name="expand">True</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">False</property>
</packing> </packing>
</child> </child>
@ -9870,9 +9972,9 @@
</child> </child>
</widget> </widget>
<packing> <packing>
<property name="padding">6</property> <property name="padding">0</property>
<property name="expand">False</property> <property name="expand">True</property>
<property name="fill">False</property> <property name="fill">True</property>
</packing> </packing>
</child> </child>
</widget> </widget>