From b9d8abee1464b2950bd6b0447a521a7806d3912c Mon Sep 17 00:00:00 2001 From: Alex Roitman Date: Sat, 18 Sep 2004 23:39:40 +0000 Subject: [PATCH] * src/DateEdit.py (DateEdit): Take care of both the button and the LED pixmap now; Invoke DateEditorDialog if the button is pressed; (DateEditorDialog): Correct the use of constants; adjust the date on the calendar change; preserve the old date unless OK was pressed; * src/AddrEdit.py: Remove date editor callback in favor of DateEdit. * src/EditPerson.py: Remove date editor callback in favor of DateEdit. * src/EventEdit.py: Remove date editor callback in favor of DateEdit. * src/gramps.glade: Minor cleanup; remove unused signal handlers. svn: r3554 --- ChangeLog | 10 +++ src/AddrEdit.py | 6 -- src/DateEdit.py | 191 +++++++++++++++++++++++++++++++++++----------- src/EditPerson.py | 12 --- src/EventEdit.py | 13 ---- src/gramps.glade | 34 ++++----- 6 files changed, 173 insertions(+), 93 deletions(-) diff --git a/ChangeLog b/ChangeLog index fa401b443..e93e0104c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2004-09-18 Alex Roitman + * src/DateEdit.py (DateEdit): Take care of both the button and + the LED pixmap now; Invoke DateEditorDialog if the button is pressed; + (DateEditorDialog): Correct the use of constants; adjust the date + on the calendar change; preserve the old date unless OK was pressed; + * src/AddrEdit.py: Remove date editor callback in favor of DateEdit. + * src/EditPerson.py: Remove date editor callback in favor of DateEdit. + * src/EventEdit.py: Remove date editor callback in favor of DateEdit. + * src/gramps.glade: Minor cleanup; remove unused signal handlers. + 2004-09-17 Alex Roitman * src/gramps.glade: Add date_edit dialog. * src/DateEdit.py (DateEditorDialog): Add class. diff --git a/src/AddrEdit.py b/src/AddrEdit.py index 1c92e439b..045e53ed4 100644 --- a/src/AddrEdit.py +++ b/src/AddrEdit.py @@ -141,7 +141,6 @@ class AddressEditor: "on_ok_addr_clicked" : self.ok_clicked, "on_cancel_addr_clicked" : self.close, "on_addr_edit_delete_event" : self.on_delete_event, - "on_date_edit_clicked", self.on_date_edit_clicked, }) if parent_window: @@ -149,11 +148,6 @@ class AddressEditor: self.add_itself_to_menu() self.window.show() - def on_date_edit_clicked(self,obj): - date_dialog = DateEdit.DateEditorDialog(self.addr_start.checkval) - the_date = date_dialog.get_date() - print "The date was built as follows:", the_date - def on_delete_event(self,obj,b): self.close_child_windows() self.remove_itself_from_menu() diff --git a/src/DateEdit.py b/src/DateEdit.py index 3c7328215..d60854497 100644 --- a/src/DateEdit.py +++ b/src/DateEdit.py @@ -21,11 +21,16 @@ # $Id$ """ -The DateEdit interface provides visual feedback to the user via a pixamp +The DateEdit module provides classes. + +The DateEdit.DateEdit provides two visual feedback to the user via a pixamp to indicate if the assocated GtkEntry box contains a valid date. Green means complete and valid date. Yellow means a valid, but incomplete date. Red means that the date is not valid, and will be viewed as a text string instead of a date. + +The DateEdit.DateEditor provides a dialog in which the date can be +unambiguously built using UI controls such as menus and spin buttons. """ __author__ = "Donald N. Allingham" @@ -46,6 +51,7 @@ from gettext import gettext as _ import gtk import gtk.gdk import gtk.glade +import gobject #------------------------------------------------------------------------- # @@ -56,6 +62,7 @@ import Date import DateParser import DateDisplay import const +import Utils #------------------------------------------------------------------------- # @@ -63,17 +70,26 @@ import const # #------------------------------------------------------------------------- MOD_TEXT = ( - _('Regular'), _('Before'), _('After'), _('About'), - _('Range'), _('Span'), _('Text only') ) -QUAL_TEXT = ( _('Regular'), _('Estimated'), _('Calculated') ) -MONTHS_NAMES = ( - DateDisplay.DateDisplay._MONS, - DateDisplay.DateDisplay._MONS, - DateDisplay.DateDisplay._hebrew, - DateDisplay.DateDisplay._french, - DateDisplay.DateDisplay._persian, - DateDisplay.DateDisplay._islamic, - ) + (Date.MOD_NONE , _('Regular')), + (Date.MOD_BEFORE , _('Before')), + (Date.MOD_AFTER , _('After')), + (Date.MOD_ABOUT , _('About')), + (Date.MOD_RANGE , _('Range')), + (Date.MOD_SPAN , _('Span')), + (Date.MOD_TEXTONLY , _('Text only')) ) + +QUAL_TEXT = ( + (Date.QUAL_NONE, _('Regular')), + (Date.QUAL_ESTIMATED, _('Estimated')), + (Date.QUAL_CALCULATED, _('Calculated')) ) + +CAL_TO_MONTHS_NAMES = { + Date.CAL_GREGORIAN : DateDisplay.DateDisplay._MONS, + Date.CAL_JULIAN : DateDisplay.DateDisplay._MONS, + Date.CAL_HEBREW : DateDisplay.DateDisplay._hebrew, + Date.CAL_FRENCH : DateDisplay.DateDisplay._french, + Date.CAL_PERSIAN : DateDisplay.DateDisplay._persian, + Date.CAL_ISLAMIC : DateDisplay.DateDisplay._islamic } #------------------------------------------------------------------------- # @@ -88,14 +104,16 @@ class DateEdit: bad = gtk.gdk.pixbuf_new_from_file(const.bad_xpm) caution = gtk.gdk.pixbuf_new_from_file(const.caution_xpm) - def __init__(self,text_obj,pixmap_obj): + def __init__(self,text_obj,button_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.button_obj = button_obj + self.pixmap_obj = button_obj.get_child() self.text_obj.connect('focus-out-event',self.check) self.check(None,None) + self.button_obj.connect('clicked',self.invoke_date_editor) def set_calendar(self,cobj): self.check(None,None) @@ -112,6 +130,12 @@ class DateEdit: # self.pixmap_obj.set_from_pixbuf(DateEdit.caution) else: self.pixmap_obj.set_from_pixbuf(DateEdit.good) + + def invoke_date_editor(self,obj): + date_dialog = DateEditorDialog(self.checkval) + the_date = date_dialog.get_date() + self.text_obj.set_text(str(the_date)) + print "The date was built as follows:", the_date #------------------------------------------------------------------------- # @@ -120,8 +144,8 @@ class DateEdit: #------------------------------------------------------------------------- class DateEditorDialog: """ - Dialog allowing to build the date precisely, to correct defficiencies - of parsing. + Dialog allowing to build the date precisely, to correct possible + limitations of parsing and/or underlying structure of Date. """ def __init__(self,date): @@ -129,30 +153,40 @@ class DateEditorDialog: Initiate and display the dialog. """ - self.date = date + # Create self.date as a copy of the given Date object. + self.date = Date.Date(date) + # Keep the given Date object safe as self.old_date + # until we're happy with modifying and want to commit. + self.old_date = date self.top = gtk.glade.XML(const.dialogFile, "date_edit","gramps" ) self.top_window = self.top.get_widget('date_edit') + title = self.top.get_widget('title') + Utils.set_titles(self.top_window,title,_('Date selection')) self.calendar_box = self.top.get_widget('calendar_box') for name in Date.Date.calendar_names: self.calendar_box.append_text(name) self.calendar_box.set_active(self.date.get_calendar()) + self.calendar_box.connect('changed',self.switch_calendar) self.quality_box = self.top.get_widget('quality_box') - for name in QUAL_TEXT: - self.quality_box.append_text(name) - self.quality_box.set_active(self.date.get_quality()) + for item_number in range(len(QUAL_TEXT)): + self.quality_box.append_text(QUAL_TEXT[item_number][1]) + if self.date.get_quality() == QUAL_TEXT[item_number][0]: + self.quality_box.set_active(item_number) self.type_box = self.top.get_widget('type_box') - for name in MOD_TEXT: - self.type_box.append_text(name) - self.type_box.set_active(self.date.get_modifier()) + for item_number in range(len(MOD_TEXT)): + self.type_box.append_text(MOD_TEXT[item_number][1]) + if self.date.get_modifier() == MOD_TEXT[item_number][0]: + self.type_box.set_active(item_number) self.type_box.connect('changed',self.switch_type) self.start_month_box = self.top.get_widget('start_month_box') self.stop_month_box = self.top.get_widget('stop_month_box') - for name in MONTHS_NAMES[self.date.get_calendar()]: + month_names = CAL_TO_MONTHS_NAMES[self.date.get_calendar()] + for name in month_names: self.start_month_box.append_text(name) self.stop_month_box.append_text(name) self.start_month_box.set_active(self.date.get_month()) @@ -168,11 +202,13 @@ class DateEditorDialog: self.stop_year = self.top.get_widget('stop_year') self.stop_year.set_value(self.date.get_stop_year()) + # Disable second date controls if not compound date if not self.date.is_compound(): self.stop_day.set_sensitive(0) self.stop_month_box.set_sensitive(0) self.stop_year.set_sensitive(0) + # Disable the rest of controls if a text-only date if self.date.get_modifier() == Date.MOD_TEXTONLY: self.start_day.set_sensitive(0) self.start_month_box.set_sensitive(0) @@ -182,25 +218,56 @@ class DateEditorDialog: self.text_entry = self.top.get_widget('date_text_entry') self.text_entry.set_text(self.date.get_text()) - + + # The dialog is modal -- since dates don't have name, we don't + # want to have several open dialogs, since then the user will + # loose track of which is which. response = self.top_window.run() - - if response == gtk.RESPONSE_HELP: - print "Help is not hooked up yet, sorry. Exiting now." - elif response == gtk.RESPONSE_OK: - self.build_date_from_ui() self.top_window.destroy() + if response == gtk.RESPONSE_HELP: + # Here be help :-) + print "Help is not hooked up yet, sorry. Exiting now." + elif response == gtk.RESPONSE_OK: + (the_quality,the_modifier,the_calendar,the_value,the_text) = \ + self.build_date_from_ui() + self.old_date.set( + quality=the_quality, + modifier=the_modifier, + calendar=the_calendar, + value=the_value) + self.old_date.set_text_value(the_text) + def get_date(self): + """ + Return the current date. + """ return self.date def build_date_from_ui(self): - if self.type_box.get_active() == Date.MOD_TEXTONLY: - self.date.set_as_text(self.text_entry.get_text()) - return + """ + Collect information from the UI controls and return + 5-tuple of (quality,modifier,calendar,value,text) + """ + # It is important to not set date based on these controls. + # For example, changing the caledar makes the date inconsistent + # until the callback of the calendar menu is finished. + # We need to be able to use this function from that callback, + # so here we just report on the state of all widgets, without + # actually modifying the date yet. + + modifier = MOD_TEXT[self.type_box.get_active()][0] + text = self.text_entry.get_text() - if self.type_box.get_active() in (Date.MOD_RANGE,Date.MOD_SPAN): - date_tuple = ( + if modifier == Date.MOD_TEXTONLY: + date.set_as_text(self.text_entry.get_text()) + return (Date.QUAL_NONE,Date.MOD_TEXTONLY,Date.CAL_GREGORIAN, + Date.EMPTY,text) + + quality = QUAL_TEXT[self.quality_box.get_active()][0] + + if modifier in (Date.MOD_RANGE,Date.MOD_SPAN): + value = ( self.start_day.get_value_as_int(), self.start_month_box.get_active(), self.start_year.get_value_as_int(), @@ -210,24 +277,25 @@ class DateEditorDialog: self.stop_year.get_value_as_int(), False) else: - date_tuple = ( + value = ( self.start_day.get_value_as_int(), self.start_month_box.get_active(), self.start_year.get_value_as_int(), False) - self.date.set( - quality=self.quality_box.get_active(), - modifier=self.type_box.get_active(), - calendar=self.calendar_box.get_active(), - value=date_tuple) - self.date.set_text_value(self.text_entry.get_text()) + calendar = self.calendar_box.get_active() + return (quality,modifier,calendar,value,text) def switch_type(self,obj): """ Disable/enable various date controls depending on the date type selected via the menu. """ - if self.type_box.get_active() in (Date.MOD_RANGE,Date.MOD_SPAN): + + the_modifier = MOD_TEXT[self.type_box.get_active()][0] + + # Disable/enable second date controls based on whether + # the type allows compound dates + if the_modifier in (Date.MOD_RANGE,Date.MOD_SPAN): stop_date_sensitivity = 1 else: stop_date_sensitivity = 0 @@ -235,9 +303,44 @@ class DateEditorDialog: self.stop_month_box.set_sensitive(stop_date_sensitivity) self.stop_year.set_sensitive(stop_date_sensitivity) - date_sensitivity = not self.type_box.get_active() == Date.MOD_TEXTONLY + # Disable/enable the rest of the controls if the type is text-only. + date_sensitivity = not the_modifier == Date.MOD_TEXTONLY self.start_day.set_sensitive(date_sensitivity) self.start_month_box.set_sensitive(date_sensitivity) self.start_year.set_sensitive(date_sensitivity) self.calendar_box.set_sensitive(date_sensitivity) self.quality_box.set_sensitive(date_sensitivity) + + def switch_calendar(self,obj): + """ + Change month names and convert the date on the calendar + selected via the menu. + """ + + 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() + self.date.set( + quality=the_quality, + modifier=the_modifier, + calendar=old_cal, + value=the_value) + self.date.set_text_value(the_text) + + self.date.convert_calendar(new_cal) + + self.start_month_box.get_model().clear() + self.stop_month_box.get_model().clear() + month_names = CAL_TO_MONTHS_NAMES[new_cal] + for name in month_names: + self.start_month_box.append_text(name) + self.stop_month_box.append_text(name) + + self.start_day.set_value(self.date.get_day()) + self.start_month_box.set_active(self.date.get_month()) + self.start_year.set_value(self.date.get_year()) + self.stop_day.set_value(self.date.get_stop_day()) + self.stop_month_box.set_active(self.date.get_stop_month()) + self.stop_year.set_value(self.date.get_stop_year()) diff --git a/src/EditPerson.py b/src/EditPerson.py index 1393b5067..7e0272994 100644 --- a/src/EditPerson.py +++ b/src/EditPerson.py @@ -423,8 +423,6 @@ class EditPerson: "on_gender_activate" : self.on_gender_activate, "on_givenName_focus_out_event": self.on_givenName_focus_out_event, "on_help_person_clicked" : self.on_help_clicked, - "on_edit_date_birth_clicked": self.on_edit_date_birth_clicked, - "on_edit_date_death_clicked": self.on_edit_date_death_clicked, }) self.update_birth_death() @@ -448,16 +446,6 @@ class EditPerson: self.add_itself_to_winsmenu() self.window.show() - def on_edit_date_birth_clicked(self,obj): - date_dialog = DateEdit.DateEditorDialog(self.bdate_check.checkval) - the_date = date_dialog.get_date() - print "The date was built as follows:", the_date - - def on_edit_date_death_clicked(self,obj): - date_dialog = DateEdit.DateEditorDialog(self.ddate_check.checkval) - the_date = date_dialog.get_date() - print "The date was built as follows:", the_date - def close_child_windows(self): for child_window in self.child_windows.values(): child_window.close(None) diff --git a/src/EventEdit.py b/src/EventEdit.py index 0b073fa5e..1bf8fdbce 100644 --- a/src/EventEdit.py +++ b/src/EventEdit.py @@ -213,18 +213,12 @@ class EventEditor: "on_deletephoto_clicked" : self.gallery.on_delete_media_clicked, "on_edit_properties_clicked": self.gallery.popup_change_description, "on_editphoto_clicked" : self.gallery.on_edit_media_clicked, - "on_date_edit_clicked" : self.on_date_edit_clicked, }) self.window.set_transient_for(self.parent.window) self.add_itself_to_menu() self.window.show() - def on_date_edit_clicked(self,obj): - date_dialog = DateEdit.DateEditorDialog(self.date_check.checkval) - the_date = date_dialog.get_date() - print "The date was built as follows:", the_date - def on_delete_event(self,obj,b): self.gallery.close() self.close_child_windows() @@ -273,13 +267,6 @@ class EventEditor: """Display the relevant portion of GRAMPS manual""" gnome.help_display('gramps-manual','gramps-edit-complete') - def on_menu_changed(self,obj): - cobj = obj.get_data("d") - self.date = self.dp.parse(self.date_field.get_text()) - self.date.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())) if text: diff --git a/src/gramps.glade b/src/gramps.glade index 48487e632..f0ac59a3f 100644 --- a/src/gramps.glade +++ b/src/gramps.glade @@ -8969,16 +8969,15 @@ Other - + True Invoke date editor True GTK_RELIEF_NORMAL True - - + True 0.5 0.5 @@ -8998,7 +8997,7 @@ Other - + True Invoke date editor True @@ -9007,7 +9006,7 @@ Other - + True 0.5 0.5 @@ -26428,15 +26427,14 @@ Other - + True True GTK_RELIEF_NORMAL True - - + True 0.5 0.5 @@ -26451,7 +26449,7 @@ Other 1 2 fill - + fill @@ -28684,15 +28682,14 @@ Other - + True True GTK_RELIEF_NORMAL True - - + True 0.5 0.5 @@ -30729,12 +30726,13 @@ Other True - Date selection - GRAMPS + GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False True False + gramps.png True False False @@ -30807,9 +30805,9 @@ Other 0 - + True - <b><big>Date selection</big></b> + False True GTK_JUSTIFY_LEFT @@ -30822,7 +30820,7 @@ Other 0 - False + True False @@ -31136,7 +31134,7 @@ Other GTK_UPDATE_ALWAYS False False - 0 0 2100 1 10 10 + 0 0 99999 1 10 10 7 @@ -31236,7 +31234,7 @@ Other GTK_UPDATE_ALWAYS False False - 0 0 2100 1 10 10 + 0 0 99999 1 10 10 3