gramps/src/gui/widgets/monitoredwidgets.py

600 lines
18 KiB
Python
Raw Normal View History

#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
__all__ = ["MonitoredCheckbox", "MonitoredEntry", "MonitoredSpinButton",
"MonitoredText", "MonitoredType", "MonitoredDataType",
"MonitoredMenu", "MonitoredStrMenu", "MonitoredDate",
"MonitoredComboSelectedEntry"]
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".widgets.monitoredwidgets")
import locale
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gobject
import gtk
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
import AutoComp
import DateEdit
#-------------------------------------------------------------------------
#
# MonitoredCheckbox class
#
#-------------------------------------------------------------------------
class MonitoredCheckbox(object):
def __init__(self, obj, button, set_val, get_val, on_toggle=None, readonly = False):
self.button = button
self.button.connect('toggled', self._on_toggle)
self.on_toggle = on_toggle
self.obj = obj
self.set_val = set_val
self.get_val = get_val
self.button.set_active(get_val())
self.button.set_sensitive(not readonly)
def _on_toggle(self, obj):
self.set_val(obj.get_active())
if self.on_toggle:
self.on_toggle(self.get_val())
#-------------------------------------------------------------------------
#
# MonitoredEntry class
#
#-------------------------------------------------------------------------
class MonitoredEntry(object):
def __init__(self, obj, set_val, get_val, read_only=False,
autolist=None, changed=None):
self.obj = obj
self.set_val = set_val
self.get_val = get_val
self.changed = changed
if get_val():
self.obj.set_text(get_val())
self.obj.connect('changed', self._on_change)
self.obj.set_editable(not read_only)
if autolist:
AutoComp.fill_entry(obj, autolist)
def reinit(self, set_val, get_val):
self.set_val = set_val
self.get_val = get_val
self.update()
def set_text(self, text):
self.obj.set_text(text)
def connect(self, signal, callback, *data):
self.obj.connect(signal, callback, *data)
def _on_change(self, obj):
self.set_val(unicode(obj.get_text()))
if self.changed:
self.changed(obj)
def force_value(self, value):
self.obj.set_text(value)
def get_value(self, value):
return unicode(self.obj.get_text())
def enable(self, value):
self.obj.set_sensitive(value)
self.obj.set_editable(value)
def grab_focus(self):
self.obj.grab_focus()
def update(self):
if self.get_val() is not None:
self.obj.set_text(self.get_val())
#-------------------------------------------------------------------------
#
# MonitoredSpinButton class
#
#-------------------------------------------------------------------------
class MonitoredSpinButton(object):
"""
Class for signal handling of spinbuttons.
(Code is a modified copy of MonitoredEntry)
"""
def __init__(self, obj, set_val, get_val, read_only=False,
autolist=None, changed=None):
"""
@param obj: widget to be monitored
@type obj: gtk.SpinButton
@param set_val: callback to be called when obj is changed
@param get_val: callback to be called to retrieve value for obj
@param read_only: If SpinButton is read only.
"""
self.obj = obj
self.set_val = set_val
self.get_val = get_val
self.changed = changed
if get_val():
self.obj.set_value(get_val())
self.obj.connect('value-changed', self._on_change)
self.obj.set_editable(not read_only)
if autolist:
AutoComp.fill_entry(obj,autolist)
def reinit(self, set_val, get_val):
"""
Reinitialize class with the specified callback functions.
@param set_val: callback to be called when SpinButton is changed
@param get_val: callback to be called to retrieve value for SpinButton
"""
self.set_val = set_val
self.get_val = get_val
self.update()
def set_value(self, value):
"""
Set the value of the monitored widget to the specified value.
@param value: Value to be set.
"""
self.obj.set_value(value)
def connect(self, signal, callback):
"""
Connect the signal of monitored widget to the specified callback.
@param signal: Signal prototype for which a connection should be set up.
@param callback: Callback function to be called when signal is emitted.
"""
self.obj.connect(signal, callback)
def _on_change(self, obj):
"""
Event handler to be called when the monitored widget is changed.
@param obj: Widget that has been changed.
@type obj: gtk.SpinButton
"""
self.set_val(obj.get_value())
if self.changed:
self.changed(obj)
def force_value(self, value):
"""
Set the value of the monitored widget to the specified value.
@param value: Value to be set.
"""
self.obj.set_value(value)
def get_value(self):
"""
Get the current value of the monitored widget.
@returns: Current value of monitored widget.
"""
return self.obj.get_value()
def enable(self, value):
"""
Change the property editable and sensitive of the monitored widget to value.
@param value: If widget should be editable or deactivated.
@type value: bool
"""
self.obj.set_sensitive(value)
self.obj.set_editable(value)
def grab_focus(self):
"""
Assign the keyboard focus to the monitored widget.
"""
self.obj.grab_focus()
def update(self):
"""
Updates value of monitored SpinButton with the value returned by the get_val callback.
"""
if self.get_val():
self.obj.set_value(self.get_val())
#-------------------------------------------------------------------------
#
# MonitoredText class
#
#-------------------------------------------------------------------------
class MonitoredText(object):
def __init__(self, obj, set_val, get_val, read_only=False):
self.buf = obj.get_buffer()
self.set_val = set_val
self.get_val = get_val
if get_val():
self.buf.set_text(get_val())
self.buf.connect('changed', self.on_change)
obj.set_editable(not read_only)
def on_change(self, obj):
s, e = self.buf.get_bounds()
self.set_val(unicode(self.buf.get_text(s, e, False)))
#-------------------------------------------------------------------------
#
# MonitoredType class
#
#-------------------------------------------------------------------------
class MonitoredType(object):
def __init__(self, obj, set_val, get_val, mapping, custom, readonly=False,
custom_values=None):
self.set_val = set_val
self.get_val = get_val
self.obj = obj
val = get_val()
if val:
default = val[0]
else:
default = None
self.sel = AutoComp.StandardCustomSelector(
mapping, obj, custom, default, additional=custom_values)
self.set_val(self.sel.get_values())
self.obj.set_sensitive(not readonly)
self.obj.connect('changed', self.on_change)
def reinit(self, set_val, get_val):
self.set_val = set_val
self.get_val = get_val
self.update()
def update(self):
if self.get_val():
self.sel.set_values(self.get_val())
def on_change(self, obj):
self.set_val(self.sel.get_values())
#-------------------------------------------------------------------------
#
# MonitoredDataType class
#
#-------------------------------------------------------------------------
class MonitoredDataType(object):
def __init__(self, obj, set_val, get_val, readonly=False,
custom_values=None, ignore_values=None):
"""
Constructor for the MonitoredDataType class.
@param obj: Existing ComboBoxEntry widget to use.
@type obj: gtk.ComboBoxEntry
@param set_val: The function that sets value of the type in the object
@type set_val: method
@param get_val: The function that gets value of the type in the object.
This returns a GrampsType, of which get_map returns all possible types
@type get_val: method
@param custom_values: Extra values to show in the combobox. These can be
text of custom type, tuple with type info or GrampsType class
@type : list of str, tuple or GrampsType
@ignore_values: list of values not to show in the combobox. If the result
of get_val is in these, it is not ignored
@type : list of int
"""
self.set_val = set_val
self.get_val = get_val
self.obj = obj
val = get_val()
if val:
default = int(val)
else:
default = None
map = get_val().get_map().copy()
if ignore_values :
for key in map.keys():
if key in ignore_values and key not in (None, default):
del map[key]
self.sel = AutoComp.StandardCustomSelector(
map,
obj,
get_val().get_custom(),
default,
additional=custom_values)
self.sel.set_values((int(get_val()), str(get_val())))
self.obj.set_sensitive(not readonly)
self.obj.connect('changed', self.on_change)
def reinit(self, set_val, get_val):
self.set_val = set_val
self.get_val = get_val
self.update()
def fix_value(self, value):
if value[0] == self.get_val().get_custom():
return value
else:
return (value[0], '')
def update(self):
val = self.get_val()
if isinstance(val, tuple):
self.sel.set_values(val)
else:
self.sel.set_values((int(val), str(val)))
def on_change(self, obj):
value = self.fix_value(self.sel.get_values())
self.set_val(value)
#-------------------------------------------------------------------------
#
# MonitoredMenu class
#
#-------------------------------------------------------------------------
class MonitoredMenu(object):
def __init__(self, obj, set_val, get_val, mapping,
readonly=False, changed=None):
self.set_val = set_val
self.get_val = get_val
self.changed = changed
self.obj = obj
self.change_menu(mapping)
self.obj.connect('changed', self.on_change)
self.obj.set_sensitive(not readonly)
def force(self, value):
self.obj.set_active(value)
def change_menu(self, mapping):
self.data = {}
self.model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
index = 0
for t, v in mapping:
self.model.append(row=[t, v])
self.data[v] = index
index += 1
self.obj.set_model(self.model)
self.obj.set_active(self.data.get(self.get_val(), 0))
def on_change(self, obj):
self.set_val(self.model.get_value(obj.get_active_iter(), 1))
if self.changed:
self.changed()
#-------------------------------------------------------------------------
#
# MonitoredStrMenu class
#
#-------------------------------------------------------------------------
class MonitoredStrMenu(object):
def __init__(self, obj, set_val, get_val, mapping, readonly=False):
self.set_val = set_val
self.get_val = get_val
self.obj = obj
self.model = gtk.ListStore(gobject.TYPE_STRING)
if len(mapping) > 20:
self.obj.set_wrap_width(3)
self.model.append(row=[''])
index = 0
self.data = ['']
default = get_val()
active = 0
for t, v in mapping:
self.model.append(row=[v])
self.data.append(t)
index += 1
if t == default:
active = index
self.obj.set_model(self.model)
self.obj.set_active(active)
self.obj.connect('changed', self.on_change)
self.obj.set_sensitive(not readonly)
def on_change(self, obj):
self.set_val(self.data[obj.get_active()])
#-------------------------------------------------------------------------
#
# MonitoredDate class
#
#-------------------------------------------------------------------------
class MonitoredDate(object):
def __init__(self, field, button, value, uistate, track, readonly=False):
self.date = value
self.date_check = DateEdit.DateEdit(
self.date, field, button, uistate, track)
field.set_editable(not readonly)
button.set_sensitive(not readonly)
#-------------------------------------------------------------------------
#
# MonitoredComboSelectedEntry class
#
#-------------------------------------------------------------------------
class MonitoredComboSelectedEntry(object):
"""
A MonitoredEntry driven by a Combobox to select what the entry field
works upon
"""
def __init__(self, objcombo, objentry, textlist, set_val_list,
get_val_list, default=0, read_only=False):
"""
Create a MonitoredComboSelectedEntry
Objcombo and objentry should be the gtk widgets to use
textlist is the values that must be used in the combobox
Every value needs an entry in set/get_val_list with the data retrieval
and storage method of the data entered in the entry box
Read_only should be true if no changes may be done
default is the entry in the combobox that must be preselected
"""
self.objcombo = objcombo
self.objentry = objentry
self.set_val_list = set_val_list
self.get_val_list = get_val_list
#fill the combobox, set on a specific entry
self.mapping = dict([[i,x] for (i,x) in zip(range(len(textlist)),
textlist)])
self.active_key = default
self.active_index = 0
self.__fill()
self.objcombo.clear()
self.objcombo.set_model(self.store)
cell = gtk.CellRendererText()
self.objcombo.pack_start(cell, True)
self.objcombo.add_attribute(cell, 'text', 1)
self.objcombo.set_active(self.active_index)
self.objcombo.connect('changed', self.on_combochange)
#fill the entrybox with required data
self.entry_reinit()
self.objentry.connect('changed', self._on_change_entry)
#set correct editable
self.enable(not read_only)
def __fill(self):
"""
Fill combo with data
"""
self.store = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
keys = sorted(self.mapping.keys(), key=self.__by_value_key)
for index, key in enumerate(keys):
self.store.append(row=[key, self.mapping[key]])
if key == self.active_key:
self.active_index = index
def __by_value(self, first, second):
"""
Method for sorting keys based on the values.
"""
fvalue = self.mapping[first]
svalue = self.mapping[second]
return locale.strcoll(fvalue, svalue)
def __by_value_key(self, first):
"""
Method for sorting keys based on the values.
"""
return locale.strxfrm(self.mapping[first])
def on_combochange(self, obj):
"""
callback for change on the combo, change active iter, update
associated entrybox
"""
self.active_key = self.store.get_value(self.objcombo.get_active_iter(),
0)
self.entry_reinit()
def reinit(self, set_val_list, get_val_list):
"""
The interface is attached to another object, so the methods need to be
reset.
"""
self.set_val_list = set_val_list
self.get_val_list = get_val_list
self.update()
def entry_reinit(self):
"""
Make the entry field show the value corresponding to the active key
"""
self.objentry.set_text(self.get_val_list[self.active_key]())
self.set_val = self.set_val_list[self.active_key]
self.get_val = self.get_val_list[self.active_key]
def _on_change_entry(self, obj):
"""
Callback when the entry field changes
"""
self.set_val_list[self.active_key](self.get_value_entry())
def get_value_entry(self):
return unicode(self.objentry.get_text())
def enable(self, value):
self.objentry.set_sensitive(value)
self.objentry.set_editable(value)
def update(self):
"""
Method called when object changed without interface change
Eg: name editor save brings you back to person editor that must update
"""
self.entry_reinit()