futher development of ObjectSelector

svn: r5753
This commit is contained in:
Richard Taylor 2006-01-14 22:21:56 +00:00
parent a5f80d4c11
commit 4e6804cb9e
10 changed files with 551 additions and 62 deletions

View File

@ -1,3 +1,14 @@
2006-01-14 Richard Taylor <rjt-gramps@thegrindstone.me.uk>
* src/ObjectSelector/_Constants.py: enums
* src/ObjectSelector/_Factories.py: multi object type factories
* src/ObjectSelector/_FamilyFilterFrame.py: family support
* src/ObjectSelector/_FamilyPreviewFrame.py: family support
* src/ObjectSelector/_FamilyTreeFrame.py: family support
* src/ObjectSelector/_PersonTreeFrame.py: separated out person tree
* src/ObjectSelector/_ObjectSelectorWindow.py: implemented view switching
* src/ObjectSelector/_PersonPreviewFrame.py: implemented view switching
* src/ObjectSelector/_PersonSearchCriteriaWidget.py: implemented view switching
2006-01-14 Don Allingham <don@gramps-project.org> 2006-01-14 Don Allingham <don@gramps-project.org>
* src/DisplayTabs.py: fix scrolled window * src/DisplayTabs.py: fix scrolled window
* src/EditFamily.py: delete button * src/EditFamily.py: delete button

View File

@ -0,0 +1,11 @@
class ObjectTypes(object):
PERSON = 0
FAMILY = 1
SOURCE = 2
EVENT = 3
MEDIA = 4
PLACE = 5
REPOSITORY = 6
REFERENCE = 7

View File

@ -0,0 +1,36 @@
from _Constants import ObjectTypes
from _PersonSearchCriteriaWidget import PersonSearchCriteriaWidget
from _PersonPreviewFrame import PersonPreviewFrame
from _PersonTreeFrame import PersonTreeFrame
from _FamilyFilterFrame import FamilyFilterFrame
from _FamilyPreviewFrame import FamilyPreviewFrame
from _FamilyTreeFrame import FamilyTreeFrame
class FilterFactory(object):
__frame_creators = {ObjectTypes.PERSON: PersonSearchCriteriaWidget,
ObjectTypes.FAMILY: FamilyFilterFrame}
def get_frame(self,object_type,dbstate):
return self.__class__.__frame_creators[object_type](dbstate)
class PreviewFactory(object):
__frame_creators = {ObjectTypes.PERSON: PersonPreviewFrame,
ObjectTypes.FAMILY: FamilyPreviewFrame}
def get_frame(self,object_type,dbstate):
return self.__class__.__frame_creators[object_type](dbstate)
class TreeFactory(object):
__frame_creators = {ObjectTypes.PERSON: PersonTreeFrame,
ObjectTypes.FAMILY: FamilyTreeFrame}
def get_frame(self,object_type,dbstate):
return self.__class__.__frame_creators[object_type](dbstate)

View File

@ -0,0 +1,159 @@
import gtk
import gobject
from _IntEdit import IntEdit
class FamilyFilterFrame(gtk.Frame):
__gproperties__ = {}
__gsignals__ = {
}
__default_border_width = 5
def __init__(self,dbstate,label="Filter"):
gtk.Frame.__init__(self,label)
align = gtk.Alignment()
# Gramps ID
id_check = gtk.CheckButton()
id_label = gtk.Label("Gramps ID")
id_label.set_alignment(xalign=0,yalign=0.5)
id_edit = gtk.Entry()
id_edit.set_sensitive(False)
id_check.connect('toggled',lambda b: id_edit.set_sensitive(id_check.get_active()))
# Name
name_check = gtk.CheckButton()
name_label = gtk.Label("Name")
name_label.set_alignment(xalign=0,yalign=0.5)
name_edit = gtk.Entry()
name_edit.set_sensitive(False)
name_check.connect('toggled',lambda b: name_edit.set_sensitive(name_check.get_active()))
# Mar
mar_check = gtk.CheckButton()
mar_check.set_alignment(xalign=0,yalign=0)
m_label = gtk.Label("Marriage Year")
m_label.set_alignment(xalign=0,yalign=0)
m_edit = IntEdit()
m_edit.set_sensitive(False)
m_before = gtk.RadioButton(group=None,label="Before")
m_before.set_sensitive(False)
m_after = gtk.RadioButton(m_before,"After")
m_after.set_sensitive(False)
m_before.set_active(True)
m_unknown = gtk.CheckButton("Include Unknown")
m_unknown.set_sensitive(False)
m_unknown.set_active(True)
mar_check.connect('toggled',lambda b: m_edit.set_sensitive(mar_check.get_active()))
mar_check.connect('toggled',lambda b: m_before.set_sensitive(mar_check.get_active()))
mar_check.connect('toggled',lambda b: m_after.set_sensitive(mar_check.get_active()))
mar_check.connect('toggled',lambda b: m_unknown.set_sensitive(mar_check.get_active()))
m_inner_box = gtk.HBox()
m_inner_box.pack_start(m_before)
m_inner_box.pack_start(m_after)
# Filter
filter_check = gtk.CheckButton()
filter_label = gtk.Label("Filter")
filter_label.set_alignment(xalign=0,yalign=0.5)
filter_combo = gtk.combo_box_new_text()
filter_combo.append_text("Male")
filter_combo.append_text("Female")
filter_combo.append_text("Unknown")
filter_combo.set_active(2)
filter_combo.set_sensitive(False)
filter_check.connect('toggled',lambda b: filter_combo.set_sensitive(filter_check.get_active()))
# table layout
table = gtk.Table(3,6,False)
table.set_row_spacings(5)
table.set_col_spacings(5)
label_col = 0
check_col = 1
control_col = 2
current_row = 0
table.attach(id_check,check_col,check_col+1,current_row,current_row+1,xoptions=False,yoptions=False)
table.attach(id_label,label_col,label_col+1,current_row,current_row+1,xoptions=gtk.FILL,yoptions=False)
table.attach(id_edit,control_col,control_col+1,current_row,current_row+1,xoptions=gtk.EXPAND|gtk.FILL,yoptions=False)
current_row +=1
table.attach(name_check,check_col,check_col+1,current_row,current_row+1,xoptions=False,yoptions=False)
table.attach(name_label,label_col,label_col+1,current_row,current_row+1,xoptions=gtk.FILL,yoptions=False)
table.attach(name_edit,control_col,control_col+1,current_row,current_row+1,xoptions=gtk.EXPAND|gtk.FILL,yoptions=False)
current_row +=1
table.attach(mar_check,check_col,check_col+1,current_row,current_row+1,xoptions=False,yoptions=False)
table.attach(m_label,label_col,label_col+1,current_row,current_row+1,xoptions=gtk.FILL,yoptions=False)
table.attach(m_edit,control_col,control_col+1,current_row,current_row+1,xoptions=gtk.EXPAND|gtk.FILL,yoptions=False)
current_row +=1
table.attach(m_inner_box,control_col,control_col+1,current_row,current_row+1,xoptions=gtk.EXPAND|gtk.FILL,yoptions=False)
current_row +=1
table.attach(m_unknown,control_col,control_col+1,current_row,current_row+1,xoptions=gtk.EXPAND|gtk.FILL,yoptions=False)
current_row +=1
table.attach(filter_check,check_col,check_col+1,current_row,current_row+1,xoptions=False,yoptions=False)
table.attach(filter_label,label_col,label_col+1,current_row,current_row+1,xoptions=gtk.FILL,yoptions=False)
table.attach(filter_combo,control_col,control_col+1,current_row,current_row+1,xoptions=gtk.EXPAND|gtk.FILL,yoptions=False)
# Apply
apply_button = gtk.Button(stock=gtk.STOCK_APPLY)
# Outer box
outer_box = gtk.VBox()
outer_box.pack_start(table,True,True)
outer_box.pack_start(apply_button,False,False)
outer_box.set_border_width(self.__class__.__default_border_width/2)
outer_box.set_spacing(self.__class__.__default_border_width/2)
align.add(outer_box)
align.set_padding(self.__class__.__default_border_width,
self.__class__.__default_border_width,
self.__class__.__default_border_width,
self.__class__.__default_border_width)
self.add(align)
if gtk.pygtk_version < (2,8,0):
gobject.type_register(FamilyFilterFrame)
if __name__ == "__main__":
w = gtk.Window()
f = FamilyFilterFrame()
w.add(f)
w.show_all()
gtk.main()

View File

@ -0,0 +1,67 @@
import gtk
import gobject
class FamilyPreviewFrame(gtk.Frame):
__gproperties__ = {}
__gsignals__ = {
}
__default_border_width = 5
def __init__(self,dbstate,label="Preview"):
gtk.Frame.__init__(self,label)
align = gtk.Alignment()
# Image
image = gtk.Image()
# test image
image.set_from_file("../flist.svg")
image_frame = gtk.Frame()
image_frame.add(image)
# Text
label = gtk.Label()
label.set_use_markup(True)
label.set_line_wrap(True)
label.set_justify(gtk.JUSTIFY_LEFT)
label.set_alignment(xalign=0.1,yalign=0.1)
label.set_markup("<b>Father:</b> Joe Blogs\n"
"<b>Mother:</b> Joe Blogs\n"
"<b>m:</b> 1906\n")
# box
box = gtk.VBox()
box.pack_start(image_frame)
box.pack_start(label)
# align
align.add(box)
align.set_padding(self.__class__.__default_border_width,
self.__class__.__default_border_width,
self.__class__.__default_border_width,
self.__class__.__default_border_width)
align.set(0.5,0.5,
1.0,1.0)
self.add(align)
if gtk.pygtk_version < (2,8,0):
gobject.type_register(FamilyPreviewFrame)
if __name__ == "__main__":
w = gtk.Window()
f = PersonPreviewFrame()
w.add(f)
w.show_all()
gtk.main()

View File

@ -0,0 +1,73 @@
import gtk
import gobject
from DisplayModels import FamilyModel
class FamilyTreeFrame(gtk.Frame):
__gproperties__ = {}
__gsignals__ = {
}
__default_border_width = 5
def __init__(self,dbstate):
gtk.Frame.__init__(self)
self._dbstate = dbstate
self._list = gtk.TreeView()
self._list.set_rules_hint(True)
self._list.set_headers_visible(True)
self._list.set_headers_clickable(True)
#self._list.connect('button-press-event',self._button_press)
#self._list.connect('key-press-event',self._key_press)
# Add columns
columns = [['ID',0],
['Father',1],
['Mother',2],
['Type',3],
['Change',4]]
for field in columns:
column = gtk.TreeViewColumn(field[0], gtk.CellRendererText(), text=field[1])
column.set_resizable(True)
column.set_min_width(75)
column.set_clickable(True)
self._list.append_column(column)
scrollwindow = gtk.ScrolledWindow()
scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scrollwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN)
scrollwindow.add(self._list)
self._inactive = False
self._selection = self._list.get_selection()
#self._selection.connect('changed',self._row_changed)
self.add(scrollwindow)
self.set_model(self._dbstate.db)
def set_model(self,db):
self._model = FamilyModel(db)
self._list.set_model(self._model)
if gtk.pygtk_version < (2,8,0):
gobject.type_register(FamilyTreeFrame)
if __name__ == "__main__":
w = ObjectSelectorWindow()
w.show_all()
w.connect("destroy", gtk.main_quit)
gtk.main()

View File

@ -1,9 +1,37 @@
#for debug, remove later
import sys
sys.path.append("..")
import gtk import gtk
import gobject import gobject
import _Factories
from _Constants import ObjectTypes
from _PersonSearchCriteriaWidget import PersonSearchCriteriaWidget from _PersonSearchCriteriaWidget import PersonSearchCriteriaWidget
from _PersonPreviewFrame import PersonPreviewFrame from _PersonPreviewFrame import PersonPreviewFrame
class _ObjectTypeWidgets(object):
def __init__(self):
self.filter_frame = None
self.preview_frame = None
self.tree_frame = None
def show(self):
self.filter_frame.show_all()
self.preview_frame.show_all()
self.tree_frame.show_all()
def hide(self):
self.filter_frame.hide_all()
self.preview_frame.hide_all()
self.tree_frame.hide_all()
OBJECT_LIST = [ObjectTypes.PERSON, ObjectTypes.FAMILY,
ObjectTypes.SOURCE, ObjectTypes.EVENT,
ObjectTypes.MEDIA, ObjectTypes.PLACE,
ObjectTypes.REPOSITORY, ObjectTypes.REFERENCE]
class ObjectSelectorWindow(gtk.Window): class ObjectSelectorWindow(gtk.Window):
__gproperties__ = {} __gproperties__ = {}
@ -13,104 +41,116 @@ class ObjectSelectorWindow(gtk.Window):
__default_border_width = 5 __default_border_width = 5
def __init__(self):
def __init__(self,
dbstate,
default_object_type = ObjectTypes.PERSON,
object_list = OBJECT_LIST):
gtk.Window.__init__(self) gtk.Window.__init__(self)
self._dbstate = dbstate
self._object_list = object_list
self.set_title("Add Person") self.set_title("Add Person")
# Selected object label # Selected object label
label = gtk.Label("Selected:") label = gtk.Label("Selected:")
label.set_alignment(xalign=1,yalign=0.5) label.set_alignment(xalign=1,yalign=0.5)
label.show()
sel_label = gtk.Label("No Selected Object") sel_label = gtk.Label("No Selected Object")
sel_frame = gtk.Frame() sel_frame = gtk.Frame()
sel_frame.set_shadow_type(gtk.SHADOW_IN) sel_frame.set_shadow_type(gtk.SHADOW_IN)
sel_frame.set_border_width(self.__class__.__default_border_width*2) sel_frame.set_border_width(self.__class__.__default_border_width*2)
sel_frame.add(sel_label) sel_frame.add(sel_label)
sel_frame.show()
label_box = gtk.HBox() label_box = gtk.HBox()
label_box.pack_start(label,False,False) label_box.pack_start(label,False,False)
label_box.pack_start(sel_frame,True,True) label_box.pack_start(sel_frame,True,True)
label_box.show()
# Object select # Object select
obj_label = gtk.Label("Show") obj_label = gtk.Label("Show")
obj_label.set_alignment(xalign=1,yalign=0.5) obj_label.set_alignment(xalign=1,yalign=0.5)
obj_label.show()
person_pixbuf = gtk.gdk.pixbuf_new_from_file("../person.svg") person_pixbuf = gtk.gdk.pixbuf_new_from_file("../person.svg")
flist_pixbuf = gtk.gdk.pixbuf_new_from_file("../flist.svg") flist_pixbuf = gtk.gdk.pixbuf_new_from_file("../flist.svg")
tool_list = gtk.ListStore(gtk.gdk.Pixbuf, str,int) self._tool_list = gtk.ListStore(gtk.gdk.Pixbuf, str,int)
tool_list.append([person_pixbuf,'People',0]) self._tool_list.append([person_pixbuf,'People',ObjectTypes.PERSON])
tool_list.append([flist_pixbuf,'Families',1]) self._tool_list.append([flist_pixbuf,'Families',ObjectTypes.FAMILY])
tool_list.append([person_pixbuf,'Events',2]) self._tool_list.append([person_pixbuf,'Events',ObjectTypes.EVENT])
tool_combo = gtk.ComboBox(tool_list) self._tool_combo = gtk.ComboBox(self._tool_list)
icon_cell = gtk.CellRendererPixbuf() icon_cell = gtk.CellRendererPixbuf()
label_cell = gtk.CellRendererText() label_cell = gtk.CellRendererText()
tool_combo.pack_start(icon_cell, True) self._tool_combo.pack_start(icon_cell, True)
tool_combo.pack_start(label_cell, True) self._tool_combo.pack_start(label_cell, True)
tool_combo.add_attribute(icon_cell, 'pixbuf', 0) self._tool_combo.add_attribute(icon_cell, 'pixbuf', 0)
tool_combo.add_attribute(label_cell, 'text', 1) self._tool_combo.add_attribute(label_cell, 'text', 1)
tool_combo.set_active(0) self._tool_combo.set_active(0)
self._tool_combo.show()
self._tool_combo.connect('changed', lambda c: self._set_object_type(self._tool_list.get_value(c.get_active_iter(),2)))
tool_box = gtk.HBox() tool_box = gtk.HBox()
tool_box.pack_start(obj_label,False,False) tool_box.pack_start(obj_label,False,False)
tool_box.pack_start(tool_combo,False,False) tool_box.pack_start(self._tool_combo,False,False)
tool_box.show()
# Top box # Top box
top_box = gtk.HBox() top_box = gtk.HBox()
top_box.pack_start(tool_box,False,False) top_box.pack_start(tool_box,False,False)
top_box.pack_start(label_box,True,True) top_box.pack_start(label_box,True,True)
top_box.show()
# Filters
person_filter = PersonSearchCriteriaWidget()
# Preview
person_preview_frame = PersonPreviewFrame("Preview")
# Trees
# dummy data for testing
self.treestore = gtk.TreeStore(str)
# we'll add some data now - 4 rows with 3 child rows each
for parent in range(4):
piter = self.treestore.append(None, ['parent %i' % parent])
for child in range(3):
self.treestore.append(piter, ['child %i of parent %i' %
(child, parent)])
self.person_tree = gtk.TreeView(self.treestore)
self.tvcolumn = gtk.TreeViewColumn('Column 0')
self.person_tree.append_column(self.tvcolumn)
self.cell = gtk.CellRendererText()
self.tvcolumn.pack_start(self.cell, True)
self.tvcolumn.add_attribute(self.cell, 'text', 0)
self.person_tree.set_search_column(0)
self.tvcolumn.set_sort_column_id(0)
self.person_tree.set_reorderable(True)
p_tree_frame = gtk.Frame() # Create the widgets for each of the object types
p_tree_frame.add(self.person_tree)
p_tree_frame.set_shadow_type(gtk.SHADOW_IN)
# paned
self._object_frames = {}
vbox = gtk.VBox() vbox = gtk.VBox()
vbox.pack_start(person_preview_frame,True,True) vbox.show()
vbox.pack_start(person_filter,True,True)
vbox2 = gtk.VBox()
vbox2.show()
pane = gtk.HPaned() pane = gtk.HPaned()
pane.pack1(p_tree_frame,True,False) pane.show()
for object_type in object_list:
self._object_frames[object_type] = _ObjectTypeWidgets()
# Filters
self._object_frames[object_type].filter_frame = _Factories.FilterFactory().get_frame(object_type,dbstate)
# Preview
self._object_frames[object_type].preview_frame = _Factories.PreviewFactory().get_frame(object_type,dbstate)
# Tree
self._object_frames[object_type].tree_frame = _Factories.TreeFactory().get_frame(object_type,dbstate)
vbox.pack_start(self._object_frames[object_type].preview_frame,True,True)
vbox.pack_start(self._object_frames[object_type].filter_frame,True,True)
vbox2.pack_start(self._object_frames[object_type].tree_frame,True,True)
self._set_object_type(default_object_type)
pane.pack1(vbox2,True,False)
pane.pack2(vbox,False,True) pane.pack2(vbox,False,True)
pane_align = gtk.Alignment() pane_align = gtk.Alignment()
@ -120,16 +160,18 @@ class ObjectSelectorWindow(gtk.Window):
self.__class__.__default_border_width, self.__class__.__default_border_width,
self.__class__.__default_border_width) self.__class__.__default_border_width)
pane_align.set(0.5,0.5,1,1) pane_align.set(0.5,0.5,1,1)
pane_align.show()
# Bottom buttons # Bottom buttons
add_button = gtk.Button(stock=gtk.STOCK_ADD) add_button = gtk.Button(stock=gtk.STOCK_ADD)
add_button.set_sensitive(False) add_button.set_sensitive(False)
add_button.show()
cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL) cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL)
cancel_button.show()
cancel_button.connect_object("clicked", gtk.Widget.destroy, self) cancel_button.connect_object("clicked", gtk.Widget.destroy, self)
bottom_button_bar = gtk.HButtonBox() bottom_button_bar = gtk.HButtonBox()
@ -138,13 +180,14 @@ class ObjectSelectorWindow(gtk.Window):
bottom_button_bar.set_border_width(self.__class__.__default_border_width) bottom_button_bar.set_border_width(self.__class__.__default_border_width)
bottom_button_bar.add(cancel_button) bottom_button_bar.add(cancel_button)
bottom_button_bar.add(add_button) bottom_button_bar.add(add_button)
bottom_button_bar.show()
box = gtk.VBox() box = gtk.VBox()
box.pack_start(top_box,False,False) box.pack_start(top_box,False,False)
box.pack_start(pane_align,True,True) box.pack_start(pane_align,True,True)
box.pack_start(bottom_button_bar,False,False) box.pack_start(bottom_button_bar,False,False)
box.show()
align = gtk.Alignment() align = gtk.Alignment()
align.set_padding(self.__class__.__default_border_width, align.set_padding(self.__class__.__default_border_width,
self.__class__.__default_border_width, self.__class__.__default_border_width,
@ -152,18 +195,56 @@ class ObjectSelectorWindow(gtk.Window):
self.__class__.__default_border_width) self.__class__.__default_border_width)
align.set(0.5,0.5,1,1) align.set(0.5,0.5,1,1)
align.add(box) align.add(box)
align.show()
self.add(align) self.add(align)
def _set_object_type(self,selected_object_type):
# enable default
self._object_frames[selected_object_type].show()
# disable all the others
[ self._object_frames[object_type].hide() for object_type in self._object_list
if object_type != selected_object_type]
store = self._tool_list
it = store.get_iter_first()
while it:
if store.get(it, 2)[0] == selected_object_type:
break
it = store.iter_next(it)
if it != None:
self._tool_combo.set_active_iter(it)
if gtk.pygtk_version < (2,8,0): if gtk.pygtk_version < (2,8,0):
gobject.type_register(PersonSearchCriteriaWidget) gobject.type_register(PersonSearchCriteriaWidget)
if __name__ == "__main__": if __name__ == "__main__":
w = ObjectSelectorWindow()
w.show_all() import GrampsDb
import const
def cb(d):
pass
db = GrampsDb.gramps_db_factory(const.app_gramps)()
db.load("/home/gramps/lib/gramps.rjt/gramps2.grdb",
cb, # callback
"w")
class D:
pass
dbstate = D()
dbstate.db = db
w = ObjectSelectorWindow(dbstate=dbstate,
default_object_type = ObjectTypes.FAMILY,
object_list=[ObjectTypes.PERSON,ObjectTypes.FAMILY])
w.show()
w.connect("destroy", gtk.main_quit) w.connect("destroy", gtk.main_quit)
gtk.main() gtk.main()

View File

@ -10,7 +10,7 @@ class PersonPreviewFrame(gtk.Frame):
__default_border_width = 5 __default_border_width = 5
def __init__(self,label="Filter"): def __init__(self,dbstate,label="Preview"):
gtk.Frame.__init__(self,label) gtk.Frame.__init__(self,label)
align = gtk.Alignment() align = gtk.Alignment()

View File

@ -12,7 +12,7 @@ class PersonSearchCriteriaWidget(gtk.Frame):
__default_border_width = 5 __default_border_width = 5
def __init__(self,label="Filter"): def __init__(self,dbstate,label="Filter"):
gtk.Frame.__init__(self,label) gtk.Frame.__init__(self,label)
align = gtk.Alignment() align = gtk.Alignment()

View File

@ -0,0 +1,51 @@
import gtk
import gobject
class PersonTreeFrame(gtk.Frame):
__gproperties__ = {}
__gsignals__ = {
}
__default_border_width = 5
def __init__(self,dbstate):
gtk.Frame.__init__(self)
# dummy data for testing
self.treestore = gtk.TreeStore(str)
# we'll add some data now - 4 rows with 3 child rows each
for parent in range(4):
piter = self.treestore.append(None, ['parent %i' % parent])
for child in range(3):
self.treestore.append(piter, ['child %i of parent %i' %
(child, parent)])
self.person_tree = gtk.TreeView(self.treestore)
self.tvcolumn = gtk.TreeViewColumn('Column 0')
self.person_tree.append_column(self.tvcolumn)
self.cell = gtk.CellRendererText()
self.tvcolumn.pack_start(self.cell, True)
self.tvcolumn.add_attribute(self.cell, 'text', 0)
self.person_tree.set_search_column(0)
self.tvcolumn.set_sort_column_id(0)
self.person_tree.set_reorderable(True)
self.add(self.person_tree)
self.set_shadow_type(gtk.SHADOW_IN)
if gtk.pygtk_version < (2,8,0):
gobject.type_register(PersonTreeFrame)
if __name__ == "__main__":
w = ObjectSelectorWindow()
w.show_all()
w.connect("destroy", gtk.main_quit)
gtk.main()