From bd0bcae0e46625f3dd620c0d367f0d469271638e Mon Sep 17 00:00:00 2001 From: Don Allingham Date: Sun, 14 Oct 2001 20:47:38 +0000 Subject: [PATCH] Added David's birth order changing svn: r470 --- gramps/TODO | 44 ++++++++++- gramps/src/EditPerson.py | 77 +++++++++++++++++++ gramps/src/RelLib.py | 4 + gramps/src/gramps.glade | 151 +++++++++++++++++++++++++++++++++----- gramps/src/gramps_main.py | 145 +++++++++++++++++++++++++++++++++++- gramps/src/sort.py | 20 +---- 6 files changed, 395 insertions(+), 46 deletions(-) diff --git a/gramps/TODO b/gramps/TODO index 7acf1a3bc..f966bd505 100644 --- a/gramps/TODO +++ b/gramps/TODO @@ -1,8 +1,44 @@ +* Allow for multiple notes. A tabbed interface would be really useful, + since there are no titles for notes. Not all objects would necessarily + need multiple notes. Determine which ones should and shouldn't. +* Drag and drop inside a gallery to allow for reordering of media objects. + This would allow for the elimination of the rather lame "Make Primary" + option. +* Drag and drop should display the icon we are dragging instead of just + the default icon. Nautilus does this very effectively, and GTK has + support for this. +* Provide an "import" of a gramps package. Not too difficult to do this, + since there is already a ReadTarFile class which will unpackage the + file. Needs have an interface built around it. +* Catch uncaught exceptions at the top level, notifiy the user, and + store the results in a file that can be emailed. Have the start of + this with the gramps.err file, but most users don't realize that + this file has been created. Some type of notification is needed. +* Allow an image to be dropped onto the image box on the first tab of + the EditPerson dialog. This would make that image the first in the + photo list as well. +* Speed up the reading of the database. The python XML routines are not + as fast as I would like, and it can take a minute or so to read a + large database. This is way too slow. +* Progress report on the WebPage report generation. I've been told that + for large databases, this can take up to about 10 minutes. A progress + bar would give people an indication of where they are in the process, + and an indication that gramps has not locked up on them. +* GEDCOM import should use the GEDCOM ID values as the GRAMPS ids if the + current database is empty. This would help us in the future if we want + to do an incremental update. Having the GEDCOM ID and the gramps ID + match up would be a good indication that these are the same people. + For example, @F001@ would become F001. +* Completely revamp the merge utility. +* Finish the generic load of revision control interfaces to allow a + revision control plugin system. Most of the work is already done. +* Extend the gramps package exporting to export to a ISO-9660 CD-ROM + image. Thumbnails would need to be exported for this as well, since + the CD-ROM would be read-only after burning. +* Disable the save buttons if gramps database is marked read-only. Disable + the adding of media objects as well, since this will cause gramps to + try to create a thumbnail in a readonly database. * Dates do not understand alternate calendars -* There are no sophisticated functions at all yet, such as merging of - databases or finding duplicate people. -* There are no logic rules yet, such as warning if a parent's birthday - is after a child's. * OpenOffice zip file is not handled very gracefully. Uses the "system" call to generate the zip file using the hard coded path of /usr/bin/zip. Python 2.0 provides a zip interface, so this may need to hold off until diff --git a/gramps/src/EditPerson.py b/gramps/src/EditPerson.py index 077c886de..071e540d7 100644 --- a/gramps/src/EditPerson.py +++ b/gramps/src/EditPerson.py @@ -48,6 +48,7 @@ import Config from RelLib import * import RelImage import ImageSelect +import sort _ = intl.gettext @@ -618,6 +619,16 @@ class EditPerson: if not self.person.getBirth().are_equal(self.birth): self.person.setBirth(self.birth) + + # Update each of the families child lists to reflect any + # change in ordering due to the new birth date + family = self.person.getMainFamily() + if (family): + new_order = reorder_child_list(self.person,family.getChildList()) + family.setChildList(new_order) + for (family, rel1, rel2) in self.person.getAltFamilyList(): + new_order = reorder_child_list(self.person,family.getChildList()) + family.setChildList(new_order) self.death.setDate(self.ddate.get_text()) dplace_obj = utils.get_place_from_list(self.dpcombo) @@ -795,3 +806,69 @@ def cancel_callback(a): def src_changed(parent): parent.lists_changed = 1 + +#------------------------------------------------------------------------- +# +# birth_dates_in_order +# +# Check any *valid* birthdates in the list to insure that they are in +# numerically increasing order. +# +#------------------------------------------------------------------------- +def birth_dates_in_order(list): + inorder = 1 + prev_date = "00000000" + for i in range(len(list)): + child = list[i] + bday = child.getBirth().getDateObj() + child_date = sort.build_sort_birth(bday) + if (child_date == "99999999"): + continue + if (prev_date <= child_date): # <= allows for twins + prev_date = child_date + else: + inorder = 0 + return inorder + + +#------------------------------------------------------------------------- +# +# reorder_child_list +# +# Reorder the child list to put the specified person in his/her +# correct birth orde. Only check *valid* birthdates. Move the person +# as short a distance as possible. +# +#------------------------------------------------------------------------- +def reorder_child_list(person, list): + if (birth_dates_in_order(list)): + return(list) + + # Build the person's date string once + person_bday = sort.build_sort_birth(person.getBirth().getDateObj()) + + # First, see if the person needs to be moved forward in the list + index = list.index(person) + target = index + for i in range(index-1, -1, -1): + other_bday = sort.build_sort_birth(list[i].getBirth().getDateObj()) + if (other_bday == "99999999"): + continue; + if (person_bday < other_bday): + target = i + + # Now try moving to a later position in the list + if (target == index): + for i in range(index, len(list)): + other_bday = sort.build_sort_birth(list[i].getBirth().getDateObj()) + if (other_bday == "99999999"): + continue; + if (person_bday > other_bday): + target = i + + # Actually need to move? Do it now. + if (target != index): + list.remove(person) + list.insert(target,person) + return list + diff --git a/gramps/src/RelLib.py b/gramps/src/RelLib.py index 0bc110cd3..d5af514cc 100644 --- a/gramps/src/RelLib.py +++ b/gramps/src/RelLib.py @@ -1204,6 +1204,10 @@ class Family: """returns the list of children""" return self.Children + def setChildList(self, list): + """sets the list of children""" + self.Children = list + def getMarriage(self): """returns the marriage event of the Family. Obsolete""" for e in self.EventList: diff --git a/gramps/src/gramps.glade b/gramps/src/gramps.glade index 8e84453b6..0bbc5a4f9 100644 --- a/gramps/src/gramps.glade +++ b/gramps/src/gramps.glade @@ -1882,6 +1882,7 @@ GtkCList child_list 80 + Click column headers to sort. When sorted by birth date, drag and drop to reorder children. True select_row @@ -1893,23 +1894,77 @@ on_child_list_button_press_event Thu, 21 Dec 2000 20:47:47 GMT - 6 - 210,60,85,150,75,50 + + click_column + on_child_list_click_column + Mon, 08 Oct 2001 20:29:49 GMT + + + row_move + on_child_list_row_move + Mon, 08 Oct 2001 20:31:41 GMT + + 7 + 210,60,85,150,75,50,25 GTK_SELECTION_SINGLE True GTK_SHADOW_IN - GtkLabel + GtkHBox CList:title - label13 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 + hbox34 + True + 0 + + + GtkHBox + hbox35 + False + 0 + + 0 + False + False + + + + GtkLabel + CList:title + label256 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkArrow + cNameSort + 10 + 10 + False + GTK_ARROW_DOWN + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + 5 + False + True + + + @@ -1939,16 +1994,59 @@ - GtkLabel + GtkHBox CList:title - label15 - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 + hbox36 + True + 0 + + + GtkHBox + hbox37 + False + 0 + + 0 + False + False + + + + GtkLabel + CList:title + label257 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkArrow + cDateSort + 10 + 10 + GTK_ARROW_DOWN + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + @@ -1976,6 +2074,19 @@ 0 0 + + + GtkLabel + CList:title + label15 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + diff --git a/gramps/src/gramps_main.py b/gramps/src/gramps_main.py index f1f8c3a89..aece425ae 100755 --- a/gramps/src/gramps_main.py +++ b/gramps/src/gramps_main.py @@ -123,6 +123,9 @@ canvas = None sort_column = 5 sort_direct = SORT_ASCENDING DataFilter = Filter.Filter("") +c_birth_order = 6 +c_sort_column = c_birth_order +c_sort_direct = SORT_ASCENDING #------------------------------------------------------------------------- # @@ -1930,9 +1933,129 @@ def on_spouse_list_select_row(obj,row,b,c): #------------------------------------------------------------------------- # -# +# on_child_list_click_column +# +# Called when the user selects a column header on the person_list window. +# Change the sort function (column 0 is the name column, and column 2 is +# the birthdate column), set the arrows on the labels to the correct +# orientation, and then call apply_filter to redraw the list # #------------------------------------------------------------------------- +def on_child_list_click_column(clist,column): + if column == 0: + child_change_sort(clist,0,gtop.get_widget("cNameSort")) + elif (column == 3) or (column == 6): + child_change_sort(clist,6,gtop.get_widget("cDateSort")) + else: + return + + sort_child_list(clist) + if id2col.has_key(active_child): + row = clist.find_row_from_data(id2col[active_child]) + clist.moveto(row) + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +def child_change_sort(clist,column,arrow): + global c_sort_direct + global c_sort_column + + cNameArrow.hide() + cDateArrow.hide() + arrow.show() + + if c_sort_column == column: + if c_sort_direct == SORT_DESCENDING: + c_sort_direct = SORT_ASCENDING + arrow.set(GTK.ARROW_DOWN,2) + else: + c_sort_direct = SORT_DESCENDING + arrow.set(GTK.ARROW_UP,2) + else: + c_sort_direct = SORT_ASCENDING + c_sort_column = column + clist.set_sort_type(c_sort_direct) + clist.set_sort_column(c_sort_column) + clist.set_reorderable(c_sort_column == c_birth_order) + + +def sort_child_list(clist): + clist.freeze() + clist.sort() + clist.thaw() + +#------------------------------------------------------------------------- +# +# on_child_list_row_move +# +# Validate whether or not this child can be moved within the clist. +# This routine is called in the middle of the clist's callbacks, so +# the state can be confusing. If the code is being debugged, the +# display at this point shows that the list has been reordered when in +# actuality it hasn't. All accesses to the clist data structure +# reference the state just prior to the "move". +# +# This routine must keep/compute its own list indices as the functions +# list.remove(), list.insert(), list.reverse() etc. do not affect the +# values returned from the list.index() routine. +# +#------------------------------------------------------------------------- +def on_child_list_row_move(clist,fm,to): + family = clist.get_data("f") + + # Create a list based upon the current order of the clist + clist_order = [] + for i in range(clist.rows): + clist_order = clist_order + [clist.get_row_data(i)] + child = clist_order[fm] + + # This function deals with ascending order lists. Convert if + # necessary. + if (c_sort_direct == SORT_DESCENDING): + clist_order.reverse() + max_index = len(clist_order) - 1 + fm = max_index - fm + to = max_index - to + + # Create a new list to match the requested order + desired_order = clist_order[:fm] + clist_order[fm+1:] + desired_order = desired_order[:to] + [child] + desired_order[to:] + + # Check birth date order in the new list + if (EditPerson.birth_dates_in_order(desired_order) == 0): + clist.emit_stop_by_name("row_move") + GnomeWarningDialog(_("Invalid move. Children must be ordered by birth date.")) + return + + # OK, this birth order works too. Update the family data structures. + family.setChildList(desired_order) + + # Build a mapping of child item to list position. This would not + # be necessary if indices worked properly + i = 0 + new_order = {} + for tmp in desired_order: + new_order[tmp] = i + i = i + 1 + + # Convert the original list back to whatever ordering is being + # used by the clist itself. + if (c_sort_direct == SORT_DESCENDING): + clist_order.reverse() + + # Update the clist indices so any change of sorting works + i = 0 + for tmp in clist_order: + clist.set_text(i, c_birth_order, "%2d"%new_order[tmp]) + i = i + 1 + + # Need to save the changed order + utils.modified() + + def on_open_activate(obj): wFs = libglade.GladeXML(const.gladeFile, "dbopen") wFs.signal_autoconnect({ @@ -2875,6 +2998,10 @@ def display_marriage(family): active_child = None i = 0 + clist.set_sort_type(c_sort_direct) + clist.set_sort_column(c_sort_column) + clist.set_reorderable(c_sort_column == c_birth_order) + if family != None: if active_person.getGender() == Person.male: active_spouse = family.getMother() @@ -2882,7 +3009,7 @@ def display_marriage(family): active_spouse = family.getFather() child_list = family.getChildList() - child_list.sort(sort.by_birthdate) + # List is already sorted by birth date attr = "" for child in child_list: status = _("Unknown") @@ -2917,7 +3044,7 @@ def display_marriage(family): attr = attr + "P" clist.append([Config.nameof(child),child.getId(),\ - gender,birthday(child),status,attr]) + gender,birthday(child),status,attr,"%2d"%i]) clist.set_row_data(i,child) i=i+1 if i != 0: @@ -2925,6 +3052,8 @@ def display_marriage(family): clist.select_row(0,0) else: fv_prev.set_sensitive(0) + clist.set_data("f",family) + clist.sort() else: fv_prev.set_sensitive(0) @@ -3304,6 +3433,7 @@ def main(arg): global person_list, source_list, place_list, canvas, media_list global topWindow, preview global nameArrow, dateArrow, deathArrow + global cNameArrow, cDateArrow global mid, mtype, mdesc, mpath, mdetails rc_parse(const.gtkrcFile) @@ -3345,6 +3475,8 @@ def main(arg): ('application/x-rootwin-drop',0,1)] media_list.drag_source_set(GDK.BUTTON1_MASK|GDK.BUTTON3_MASK,t,GDK.ACTION_COPY) media_list.drag_dest_set(DEST_DEFAULT_ALL,t,GDK.ACTION_COPY|GDK.ACTION_MOVE) + cNameArrow = gtop.get_widget("cNameSort") + cDateArrow = gtop.get_widget("cDateSort") person_list.set_column_visibility(5,0) person_list.set_column_visibility(6,0) person_list.set_column_visibility(7,0) @@ -3377,6 +3509,8 @@ def main(arg): "on_canvas1_event" : on_canvas1_event, "on_child_list_button_press_event" : on_child_list_button_press_event, "on_child_list_select_row" : on_child_list_select_row, + "on_child_list_click_column" : on_child_list_click_column, + "on_child_list_row_move" : on_child_list_row_move, "on_choose_parents_clicked" : on_choose_parents_clicked, "on_contents_activate" : on_contents_activate, "on_default_person_activate" : on_default_person_activate, @@ -3436,7 +3570,10 @@ def main(arg): person_list.set_column_visibility(1,Config.id_visible) notebook.set_show_tabs(Config.usetabs) - gtop.get_widget("child_list").set_column_visibility(4,Config.show_detail) + child_list = gtop.get_widget("child_list") + child_list.set_column_visibility(4,Config.show_detail) + child_list.set_column_visibility(6,0) + child_list.set_column_visibility(7,0) if arg != None: read_file(arg) diff --git a/gramps/src/sort.py b/gramps/src/sort.py index 64701b107..324df648a 100644 --- a/gramps/src/sort.py +++ b/gramps/src/sort.py @@ -46,7 +46,7 @@ def build_sort_birth(n): d = n.start.day if d == -1: d = 99 - return "%04d%2d%2d" % (y,m,d) + return "%04d%02d%02d" % (y,m,d) #------------------------------------------------------------------------- # @@ -63,7 +63,7 @@ def build_sort_death(n): d = n.start.day if d == -1: d = 99 - return "%04d%2d%2d" % (y,m,d) + return "%04d%02d%02d" % (y,m,d) #------------------------------------------------------------------------- # @@ -158,19 +158,3 @@ def by_last_name(first, second) : #------------------------------------------------------------------------- def by_last_name_backwards(first, second) : return by_last_name(second,first) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -def by_birthdate(first, second) : - - date1 = first.getBirth().getDateObj() - date2 = second.getBirth().getDateObj() - val = compare_dates(date1,date2) - if val == 0: - return by_last_name(first,second) - return val - -