From 0843d5033adf412d51d277b95f979ac0f45b9715 Mon Sep 17 00:00:00 2001 From: Don Allingham Date: Fri, 6 Aug 2004 03:08:27 +0000 Subject: [PATCH] * src/AutoComp.py: switch over entirely to ComboBox for autocompletion * src/GenericFilter.py: support ComboBox * src/TransTable.py: sort items on getting keys * src/plugins/FilterEditor.py: support ComboBox * src/plugins/SoundGen.py: support ComboBox * src/plugins/soundex.glade: support ComboBox svn: r3346 --- ChangeLog | 9 ++ src/AutoComp.py | 277 ++---------------------------------- src/GenericFilter.py | 20 +-- src/TransTable.py | 4 +- src/Utils.py | 1 + src/plugins/FilterEditor.py | 53 +++++-- src/plugins/SoundGen.py | 7 +- src/plugins/soundex.glade | 76 ++-------- src/system_filters.xml | 6 + 9 files changed, 101 insertions(+), 352 deletions(-) diff --git a/ChangeLog b/ChangeLog index 99ed6cab1..3d1e98d0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2004-08-05 Don Allingham + * src/AutoComp.py: switch over entirely to ComboBox for + autocompletion + * src/GenericFilter.py: support ComboBox + * src/TransTable.py: sort items on getting keys + * src/plugins/FilterEditor.py: support ComboBox + * src/plugins/SoundGen.py: support ComboBox + * src/plugins/soundex.glade: support ComboBox + 2004-08-04 Don Allingham * src/AttrEdit.py: use ComboBox * src/NameEdit.py: use ComboBox diff --git a/src/AutoComp.py b/src/AutoComp.py index 387533bd2..4d255939f 100644 --- a/src/AutoComp.py +++ b/src/AutoComp.py @@ -20,22 +20,6 @@ # $Id$ -""" -Adds autocompletion to a GtkEntry box, using the passed list of -strings as the possible completions. This work was adapted from code -written by David Hampton. -""" - -__author__ = "David R. Hampton, Donald N. Allingham" -__version__ = "$Revision$" - -#------------------------------------------------------------------------- -# -# python modules -# -#------------------------------------------------------------------------- -import string - #------------------------------------------------------------------------- # # GNOME modules @@ -44,252 +28,6 @@ import string import gtk import gobject -_t = type(u'') - -def patch(n): - if type(n) != _t: - return (unicode(n).lower(),unicode(n)) - else: - return (n.lower(),n) - -#------------------------------------------------------------------------- -# -# AutoCompBase -# -#------------------------------------------------------------------------- -class AutoCompBase: - - def __init__(self,widget,plist,source=None): - """ - Creates a autocompleter for the specified GNOME/GTK widget, using the - list of strings as the completion values. The AutoCompBase class - should never be instantiated on its own. Instead, classes should be - derived from it. - - widget - widget instance the completer is assocated with - plist - List of completion strings - source - If not None, uses the completion values of an already existing AutoCompBase instance - """ - if source: - self.nlist = source.nlist - else: - self.nlist = [] - self.nlist = map(patch,plist) - self.nlist.sort() - self.nl = "xzsdkdjecsc" - self.l = 0 - self.t = type(u' ') - - def insert_text(self,entry,new_text,new_text_len,i_dont_care): - """ - Sets up a delayed (0.005 sec) handler for text completion. Text - completion cannot be handled directly in this routine because, for - some reason, the select_region() function doesn't work when called - from signal handlers. Go figure. - - Thanks to iain@nodata.demon.co.uk (in mail from 1999) for the idea - to use a timer to get away from the problems with signal handlers - and the select_region function. - """ - - # One time setup to clear selected region when user moves on - if (not entry.get_data("signal_set")): - entry.set_data("signal_set",1) - entry.connect("focus-out-event", self.lost_focus, entry) - - # Nuke the current timer if the user types fast enough - timer = entry.get_data("timer"); - if (timer): - gtk.timeout_remove(timer) - - # Setup a callback timer so we can operate outside of a signal handler - timer = gtk.timeout_add(5, self.timer_callback, entry) - entry.set_data("timer", timer); - - def lost_focus(self,entry,a,b): - """ - The entry box entry field lost focus. Go clear any selection. Why - this form of a select_region() call works in a signal handler and - the other form doesn't is a mystery. - """ - gtk.Editable.select_region(entry,0, 0) - - def timer_callback(self,entry): - """ - Perfroms the actual task of completion. This method should be - overridden in all subclasses - """ - pass - -#------------------------------------------------------------------------- -# -# AutoCombo -# -#------------------------------------------------------------------------- -class AutoCombo(AutoCompBase): - """ - Allows allow completion of the GtkCombo widget with the entries - in the passed string list. This class updates the drop down window - with the values that currently match the substring in the text box. - """ - - def __init__(self,widget,plist,source=None): - """ - Creates a autocompleter for the a GtkCombo widget, using the - list of strings as the completion values. The - - widget - GtkCombo instance the completer is assocated with - plist - List of completion strings - source - If not None, uses the completion values of an already existing - AutoCompBase instance - """ - AutoCompBase.__init__(self,widget,plist,source) - self.entry = widget - widget.entry.connect("insert-text",self.insert_text) - self.vals = [""] - self.inb = 0 - if plist and len(plist) < 250: - widget.set_popdown_strings(plist) - else: - widget.set_popdown_strings([""]) - widget.get_children()[1].hide() - - def setval(self,widget): - """Callback task called on the button release""" - - self.inb = 0 - text = unicode(self.entry.entry.get_text()) - if self.nl == string.lower(text): - gtk.Editable.set_position(self.entry.entry,self.l) - gtk.Editable.select_region(self.entry.entry,self.l,-1) - - def build_list(self,widget): - """Internal task that builds the popdown strings. This task is called when the - combo button that activates the dropdown menu is pressed - """ - self.inb = 1 - - if self.vals and len(self.vals) < 250: - if self.vals[0] == "": - self.entry.set_popdown_strings([unicode(self.entry.entry.get_text())]) - else: - self.entry.set_popdown_strings(self.vals) - else: - self.entry.set_popdown_strings([""]) - - return 1 - - def timer_callback(self,entry): - """ - The workhorse routine of file completion. This routine grabs the - current text of the entry box, and grubs through the list item - looking for any case insensitive matches. This routine relies on - public knowledge of the GtkEntry data structure, not on any private - data. - """ - # Clear any timer - timer = entry.get_data("timer"); - if timer: - gtk.timeout_remove(timer) - - if self.inb == 1: - return - - # Get the user's text - typed = unicode(entry.get_text()) - if (not typed): - return - if type(typed) != self.t: - typed = unicode(typed) - - typed_lc = string.lower(typed) - - if typed_lc == self.nl: - return - - self.l = len(typed_lc) - - self.vals = [] - - # Walk the GtkList in the entry box - for nl,n in self.nlist: - # If typed text is a substring of the label text, then fill in - # the entry field with the full text (and correcting - # capitalization), and then select all the characters that - # don't match. With the user's next keystroke these will be - # replaced if they are incorrect. - if nl[0:self.l] == typed_lc: - self.vals.append(n) - - if len(self.vals) > 0: - n = self.vals[0] - self.nl = string.lower(n) - entry.set_text(n) - # Select non-matching text from the end to the beginning: - # this preserves the visibility of the portion being typed. - ln = len(n) - gtk.Editable.set_position(entry,ln-1) - gtk.Editable.select_region(entry,ln,self.l) - else: - self.vals = [""] - -#------------------------------------------------------------------------- -# -# AutoEntry -# -#------------------------------------------------------------------------- -class AutoEntry(AutoCompBase): - """ - Allows allow completion of the GtkEntry widget with the entries - in the passed string list. - """ - def __init__(self,widget,plist,source=None): - AutoCompBase.__init__(self,widget,plist,source) - self.entry = widget - self.entry.connect("insert-text",self.insert_text) - - def timer_callback(self,entry): - """ - The workhorse routine of file completion. This routine grabs the - current text of the entry box, and grubs through the list item - looking for any case insensitive matches. This routine relies on - public knowledge of the GtkEntry data structure, not on any private - data. - """ - # Clear any timer - timer = entry.get_data("timer"); - if (timer): - gtk.timeout_remove(timer) - - # Get the user's text - typed = unicode(entry.get_text()) - - if type(typed) != self.t: - typed = unicode(typed) - - if (not typed): - return - typed_lc = string.lower(typed) - - if typed_lc == self.nl: - return - - self.l = len(typed_lc) - - # Walk the GtkList in the entry box - for nl,n in self.nlist: - # If typed text is a substring of the label text, then fill in - # the entry field with the full text (and correcting - # capitalization), and then select all the characters that - # don't match. With the user's next keystroke these will be - # replaced if they are incorrect. - if nl[0:self.l] == typed_lc: - self.nl = nl - entry.set_text(n) - gtk.Editable.set_position(entry,self.l) - gtk.Editable.select_region(entry,self.l, -1) - return - def fill_combo(combo,data_list): store = gtk.ListStore(gobject.TYPE_STRING) @@ -316,3 +54,18 @@ def fill_entry(entry,data_list): completion.set_text_column(0) entry.set_completion(completion) +def fill_option_text(combobox,data): + typelist = [] + store = gtk.ListStore(*[gobject.TYPE_STRING]) + cell = gtk.CellRendererText() + combobox.pack_start(cell,gtk.TRUE) + combobox.add_attribute(cell,'text',0) + for item in data: + print item + store.append(row=[item]) + combobox.set_model(store) + combobox.set_active(0) + +def get_option(combobox): + store = combobox.get_model() + return store.get_value(combobox.get_active_iter(),0) diff --git a/src/GenericFilter.py b/src/GenericFilter.py index e4c04f66e..b83298a7d 100644 --- a/src/GenericFilter.py +++ b/src/GenericFilter.py @@ -1557,15 +1557,17 @@ class GenericFilterList: self.filter_list.append(filter) def load(self): - try: - parser = make_parser() - parser.setContentHandler(FilterParser(self)) - if self.file[0:7] != "file://": - parser.parse("file://" + self.file) - else: - parser.parse(self.file) - except (IOError,OSError,SAXParseException): - pass + try: + parser = make_parser() + parser.setContentHandler(FilterParser(self)) + if self.file[0:7] != "file://": + parser.parse("file://" + self.file) + else: + parser.parse(self.file) + except (IOError,OSError): + pass + except SAXParseException: + print "Parser error" def fix(self,line): l = line.strip() diff --git a/src/TransTable.py b/src/TransTable.py index 2be22ab88..85059aef4 100644 --- a/src/TransTable.py +++ b/src/TransTable.py @@ -59,6 +59,8 @@ class TransTable: return self.rmap.has_key(value) def get_values(self): - return self.map.values() + values = self.map.values() + values.sort() + return values diff --git a/src/Utils.py b/src/Utils.py index 19aae49a3..c6e77bf8e 100644 --- a/src/Utils.py +++ b/src/Utils.py @@ -558,3 +558,4 @@ def get_new_filename(ext): while os.path.isfile(os.path.expanduser(_NEW_NAME_PATTERN % (ix,ext) )): ix = ix + 1 return os.path.expanduser(_NEW_NAME_PATTERN % (ix,ext)) + diff --git a/src/plugins/FilterEditor.py b/src/plugins/FilterEditor.py index 872148285..e5f08c0bb 100644 --- a/src/plugins/FilterEditor.py +++ b/src/plugins/FilterEditor.py @@ -59,9 +59,12 @@ _name2list = { _('Family event:') : const.family_events, _('Personal attribute:') : const.personal_attributes, _('Family attribute:') : const.family_attributes, - _('Relationship type:') : const.family_relations, } +_menulist = { + _('Relationship type:') : const.family_relations, + } + #------------------------------------------------------------------------- # # MyBoolean - check button with standard interface @@ -103,11 +106,11 @@ class MyInteger(gtk.SpinButton): # MyFilters - Combo box with list of filters with a standard interface # #------------------------------------------------------------------------- -class MyFilters(gtk.Combo): +class MyFilters(gtk.ComboBox): def __init__(self,filters): - gtk.Combo.__init__(self) - + gtk.ComboBox.__init__(self) + flist = [] for f in filters: flist.append(f.get_name()) @@ -117,12 +120,12 @@ class MyFilters(gtk.Combo): self.set_sensitive(0) else: self.ok = 1 - AutoComp.AutoCombo(self,flist) + AutoComp.fill_option_text(self,flist) self.show() def get_text(self): if self.ok: - return unicode(self.entry.get_text()) + return unicode(AutoComp.get_option(self)) else: return "" @@ -140,7 +143,7 @@ class MyPlaces(gtk.Entry): def __init__(self,places): gtk.Entry.__init__(self) - self.comp = AutoComp.AutoEntry(self,places) + self.comp = AutoComp.fill_entry(self,places) self.show() #------------------------------------------------------------------------- @@ -193,16 +196,33 @@ class MyID(gtk.HBox): # # #------------------------------------------------------------------------- -class MySelect(gtk.Combo): +class MySelect(gtk.ComboBoxEntry): def __init__(self,transtable): - gtk.Combo.__init__(self) - list = transtable.get_values() - list.sort() - self.set_popdown_strings(list) - self.set_value_in_list(1,0) - self.entry.set_editable(0) - self.transtable = transtable + gtk.ComboBoxEntry.__init__(self) + AutoComp.fill_combo(self,transtable.get_values()) + self.show() + + def get_text(self): + return self.transtable.find_key(unicode(self.entry.get_text())) + + def set_text(self,val): + self.entry.set_text(_(val)) + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +class MyListSelect(gtk.ComboBoxEntry): + + def __init__(self,data_list): + gtk.ComboBoxEntry.__init__(self) + new_list = [] + for item in data_list: + new_list.append(item[0]) + new_list.sort() + AutoComp.fill_combo(self,new_list) self.show() def get_text(self): @@ -595,6 +615,9 @@ class EditRule: elif _name2list.has_key(v1): data =_name2list[v1] t = MySelect(data) + elif _menulist.has_key(v1): + data =_menulist[v1] + t = MyListSelect(data) elif v == _('Inclusive:'): t = MyBoolean(_('Include original person')) else: diff --git a/src/plugins/SoundGen.py b/src/plugins/SoundGen.py index 7c95e0549..35dcb59f7 100644 --- a/src/plugins/SoundGen.py +++ b/src/plugins/SoundGen.py @@ -62,7 +62,8 @@ class SoundGen: _('SoundEx code generator')) self.value = self.glade.get_widget("value") - self.name = self.glade.get_widget("name") + self.autocomp = self.glade.get_widget("name_list") + self.name = self.autocomp.child self.name.connect('changed',self.on_apply_clicked) @@ -74,8 +75,8 @@ class SoundGen: names.append(lastname) names.sort() - self.autocomp = AutoComp.AutoCombo(self.glade.get_widget("nameList"), - names) + + AutoComp.fill_combo(self.autocomp, names) if active_person: n = active_person.get_primary_name().get_surname() diff --git a/src/plugins/soundex.glade b/src/plugins/soundex.glade index 433a9c078..cf8fd863a 100644 --- a/src/plugins/soundex.glade +++ b/src/plugins/soundex.glade @@ -138,68 +138,6 @@ - - - True - False - True - False - True - False - - - - True - Name used to generate SoundEx code - True - True - True - 0 - - True - * - False - - - - - - True - GTK_SELECTION_BROWSE - - - - True - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - - - - - - - 1 - 2 - 0 - 1 - - - - True @@ -223,6 +161,20 @@ + + + + True + + + 1 + 2 + 0 + 1 + fill + fill + + 0 diff --git a/src/system_filters.xml b/src/system_filters.xml index ca376f71c..c5bc6b331 100644 --- a/src/system_filters.xml +++ b/src/system_filters.xml @@ -1,3 +1,9 @@ + + + + + +