* 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
This commit is contained in:
Don Allingham 2004-08-06 03:08:27 +00:00
parent e2122c9d67
commit 0843d5033a
9 changed files with 101 additions and 352 deletions

View File

@ -1,3 +1,12 @@
2004-08-05 Don Allingham <dallingham@users.sourceforge.net>
* 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 <dallingham@users.sourceforge.net>
* src/AttrEdit.py: use ComboBox
* src/NameEdit.py: use ComboBox

View File

@ -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)

View File

@ -1564,8 +1564,10 @@ class GenericFilterList:
parser.parse("file://" + self.file)
else:
parser.parse(self.file)
except (IOError,OSError,SAXParseException):
except (IOError,OSError):
pass
except SAXParseException:
print "Parser error"
def fix(self,line):
l = line.strip()

View File

@ -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

View File

@ -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))

View File

@ -59,6 +59,9 @@ _name2list = {
_('Family event:') : const.family_events,
_('Personal attribute:') : const.personal_attributes,
_('Family attribute:') : const.family_attributes,
}
_menulist = {
_('Relationship type:') : const.family_relations,
}
@ -103,10 +106,10 @@ 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:
@ -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:

View File

@ -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()

View File

@ -138,68 +138,6 @@
</packing>
</child>
<child>
<widget class="GtkCombo" id="nameList">
<property name="visible">True</property>
<property name="value_in_list">False</property>
<property name="allow_empty">True</property>
<property name="case_sensitive">False</property>
<property name="enable_arrow_keys">True</property>
<property name="enable_arrows_always">False</property>
<child internal-child="entry">
<widget class="GtkEntry" id="name">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Name used to generate SoundEx code</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char" translatable="yes">*</property>
<property name="activates_default">False</property>
</widget>
</child>
<child internal-child="list">
<widget class="GtkList" id="convertwidget1">
<property name="visible">True</property>
<property name="selection_mode">GTK_SELECTION_BROWSE</property>
<child>
<widget class="GtkListItem" id="convertwidget2">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="convertwidget3">
<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</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="value">
<property name="visible">True</property>
@ -223,6 +161,20 @@
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkComboBoxEntry" id="name_list">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>

View File

@ -1,3 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<filters>
<filter name="asfd" function="and">
<rule class="Is a male">
</rule>
</filter>
<filter name="asfasdfasdf" function="and">
</filter>
</filters>