From 2334b8058d6a950d5d3b79697918663d3e37c307 Mon Sep 17 00:00:00 2001 From: Gary Burton Date: Wed, 25 Feb 2009 18:18:19 +0000 Subject: [PATCH] Bug 2616. Fixes for memory leaks in event editor svn: r12116 --- src/DisplayTabs/_BackRefList.py | 7 ++++ src/DisplayTabs/_ButtonTab.py | 9 +++++ src/DisplayTabs/_EmbeddedList.py | 4 +- src/DisplayTabs/_GalleryTab.py | 4 +- src/DisplayTabs/_GrampsTab.py | 23 +++++++++++ src/Editors/_EditEvent.py | 65 ++++++++++++++++++++------------ src/ManagedWindow.py | 24 +++++++++++- 7 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/DisplayTabs/_BackRefList.py b/src/DisplayTabs/_BackRefList.py index 7958652e3..374351c52 100644 --- a/src/DisplayTabs/_BackRefList.py +++ b/src/DisplayTabs/_BackRefList.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2007 Donald N. Allingham +# Copyright (C) 2009 Gary Burton # # 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 @@ -64,6 +65,7 @@ class BackRefList(EmbeddedList): _('_References'), refmodel) self._callback = callback self.model.connect('row-inserted', self.update_label) + self.track_ref_for_deletion("model") def update_label(self, *obj): if self.model.count > 0: @@ -99,6 +101,11 @@ class BackRefList(EmbeddedList): self.add_btn = None self.del_btn = None + self.track_ref_for_deletion("edit_btn") + self.track_ref_for_deletion("tooltips") + self.track_ref_for_deletion("add_btn") + self.track_ref_for_deletion("del_btn") + def _selection_changed(self, obj=None): if self.dirty_selection: return diff --git a/src/DisplayTabs/_ButtonTab.py b/src/DisplayTabs/_ButtonTab.py index 3e26d164a..8711a5b17 100644 --- a/src/DisplayTabs/_ButtonTab.py +++ b/src/DisplayTabs/_ButtonTab.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2006 Donald N. Allingham +# Copyright (C) 2009 Gary Burton # # 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 @@ -99,6 +100,7 @@ class ButtonTab(GrampsTab): self.dirty_selection = False GrampsTab.__init__(self,dbstate, uistate, track, name) self.tooltips = gtk.Tooltips() + self.track_ref_for_deletion("tooltips") self.create_buttons(share_button, move_buttons, jump_button) def create_buttons(self, share_button, move_buttons, jump_button): @@ -112,6 +114,9 @@ class ButtonTab(GrampsTab): self.add_btn = SimpleButton(gtk.STOCK_ADD, self.add_button_clicked) self.edit_btn = SimpleButton(gtk.STOCK_EDIT, self.edit_button_clicked) self.del_btn = SimpleButton(gtk.STOCK_REMOVE, self.del_button_clicked) + self.track_ref_for_deletion("add_btn") + self.track_ref_for_deletion("edit_btn") + self.track_ref_for_deletion("del_btn") self.tooltips.set_tip(self.add_btn, self._MSG['add']) self.tooltips.set_tip(self.edit_btn, self._MSG['edit']) @@ -120,6 +125,7 @@ class ButtonTab(GrampsTab): if share_button: self.share_btn = SimpleButton(gtk.STOCK_INDEX, self.share_button_clicked) self.tooltips.set_tip(self.share_btn, self._MSG['share']) + self.track_ref_for_deletion("share_btn") else: self.share_btn = None @@ -129,6 +135,8 @@ class ButtonTab(GrampsTab): self.down_btn = SimpleButton(gtk.STOCK_GO_DOWN, self.down_button_clicked) self.tooltips.set_tip(self.down_btn, self._MSG['down']) + self.track_ref_for_deletion("up_btn") + self.track_ref_for_deletion("down_btn") else: self.up_btn = None self.down_btn = None @@ -146,6 +154,7 @@ class ButtonTab(GrampsTab): if jump_button: self.jump_btn = SimpleButton(gtk.STOCK_JUMP_TO, self.jump_button_clicked) + self.track_ref_for_deletion("jump_btn") self.tooltips.set_tip(self.jump_btn, self._MSG['jump']) else: self.jump_btn = None diff --git a/src/DisplayTabs/_EmbeddedList.py b/src/DisplayTabs/_EmbeddedList.py index 851473775..b2ea8a8bb 100644 --- a/src/DisplayTabs/_EmbeddedList.py +++ b/src/DisplayTabs/_EmbeddedList.py @@ -73,6 +73,7 @@ class EmbeddedList(ButtonTab): # handle the selection self.selection = self.tree.get_selection() self.selection.connect('changed', self._selection_changed) + self.track_ref_for_deletion("selection") # build the columns self.columns = [] @@ -341,6 +342,7 @@ class EmbeddedList(ButtonTab): self.tree.set_rules_hint(True) self.tree.connect('button_press_event', self.double_click) self.tree.connect('key_press_event', self.key_pressed) + self.track_ref_for_deletion("tree") # create the scrolled window, and attach the treeview scroll = gtk.ScrolledWindow() @@ -428,6 +430,7 @@ class EmbeddedList(ButtonTab): column.set_sort_column_id(self._column_names[pair[1]][1]) self.columns.append(column) self.tree.append_column(column) + self.track_ref_for_deletion("columns") def rebuild(self): """ @@ -450,4 +453,3 @@ class EmbeddedList(ButtonTab): #model and tree are reset, allow _selection_changed again, and force it self.dirty_selection = False self._selection_changed() - diff --git a/src/DisplayTabs/_GalleryTab.py b/src/DisplayTabs/_GalleryTab.py index 867e09f13..874f93bfe 100644 --- a/src/DisplayTabs/_GalleryTab.py +++ b/src/DisplayTabs/_GalleryTab.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2006 Donald N. Allingham +# Copyright (C) 2009 Gary Burton # # 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 @@ -72,8 +73,8 @@ class GalleryTab(ButtonTab): def __init__(self, dbstate, uistate, track, media_list, update=None): self.iconlist = gtk.IconView() - ButtonTab.__init__(self, dbstate, uistate, track, _('_Gallery'), True) + self.track_ref_for_deletion("iconlist") self.media_list = media_list self.update = update @@ -146,6 +147,7 @@ class GalleryTab(ButtonTab): def _build_icon_model(self): self.iconmodel = gtk.ListStore(gtk.gdk.Pixbuf, gobject.TYPE_STRING, object) + self.track_ref_for_deletion("iconmodel") def _connect_icon_model(self): self.iconlist.set_model(self.iconmodel) diff --git a/src/DisplayTabs/_GrampsTab.py b/src/DisplayTabs/_GrampsTab.py index 8d647f536..bd8a156a6 100644 --- a/src/DisplayTabs/_GrampsTab.py +++ b/src/DisplayTabs/_GrampsTab.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2006 Donald N. Allingham +# Copyright (C) 2009 Gary Burton # # 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 @@ -70,6 +71,7 @@ class GrampsTab(gtk.VBox): self.uistate = uistate self.track = track self.changed = False + self.__refs_for_deletion = [] self._add_db_signal = None @@ -77,7 +79,9 @@ class GrampsTab(gtk.VBox): # for the label self.tab_name = name + self.track_ref_for_deletion("tab_name") self.label_container = self.build_label_widget() + self.track_ref_for_deletion("label_container") # build the interface self.share_btn = None @@ -116,7 +120,9 @@ class GrampsTab(gtk.VBox): name = icon self.tab_image = func(name, gtk.ICON_SIZE_MENU) + self.track_ref_for_deletion("tab_image") self.label = gtk.Label(self.tab_name) + self.track_ref_for_deletion("label") hbox.pack_start(self.tab_image) hbox.set_spacing(6) hbox.add(self.label) @@ -213,6 +219,7 @@ class GrampsTab(gtk.VBox): def set_parent_notebook(self, book): self.parent_notebook = book + self.track_ref_for_deletion("parent_notebook") def next_page(self): if self.parent_notebook: @@ -222,3 +229,19 @@ class GrampsTab(gtk.VBox): if self.parent_notebook: self.parent_notebook.prev_page() + def track_ref_for_deletion(self, ref): + """ + Record references of instance variables that need to be removed + from scope so that the class can be garbage collected + """ + if ref not in self.__refs_for_deletion: + self.__refs_for_deletion.append(ref) + + def clean_up(self): + """ + Remove any instance variables from scope which point to non-glade + GTK objects so that the class can be garbage collected. + """ + while len(self.__refs_for_deletion): + attr = self.__refs_for_deletion.pop() + delattr(self, attr) diff --git a/src/Editors/_EditEvent.py b/src/Editors/_EditEvent.py index c61b1d8e7..82748bffc 100644 --- a/src/Editors/_EditEvent.py +++ b/src/Editors/_EditEvent.py @@ -2,7 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2007 Donald N. Allingham -# 2009 Gary Burton +# Copyright (C) 2009 Gary Burton # # 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 @@ -154,38 +154,53 @@ class EditEvent(EditPrimary): window. """ notebook = gtk.Notebook() - - self.srcref_list = self._add_tab( - notebook, - SourceEmbedList(self.dbstate,self.uistate,self.track,self.obj)) - - self.note_tab = self._add_tab( - notebook, - NoteTab(self.dbstate, self.uistate, self.track, - self.obj.get_note_list(), notetype=gen.lib.NoteType.EVENT)) - - self.gallery_tab = self._add_tab( - notebook, - GalleryTab(self.dbstate, self.uistate, self.track, - self.obj.get_media_list())) - self.attr_ref_list = self._add_tab( - notebook, - AttrEmbedList(self.dbstate, self.uistate, self.track, - self.obj.get_attribute_list())) + self.source_list = SourceEmbedList(self.dbstate, + self.uistate, + self.track, + self.obj) + self._add_tab(notebook, self.source_list) + + self.note_list = NoteTab(self.dbstate, + self.uistate, + self.track, + self.obj.get_note_list(), + notetype=gen.lib.NoteType.EVENT) + self._add_tab(notebook, self.note_list) + - self.backref_tab = self._add_tab( - notebook, - EventBackRefList(self.dbstate, self.uistate, self.track, - self.dbstate.db.find_backlink_handles(self.obj.handle))) + self.gallery_list = GalleryTab(self.dbstate, + self.uistate, + self.track, + self.obj.get_media_list()) + self._add_tab(notebook, self.gallery_list) - self._setup_notebook_tabs( notebook) + self.attr_list = AttrEmbedList(self.dbstate, + self.uistate, + self.track, + self.obj.get_attribute_list()) + self._add_tab(notebook, self.attr_list) + + handle_list = self.dbstate.db.find_backlink_handles(self.obj.handle) + self.backref_list = EventBackRefList(self.dbstate, + self.uistate, + self.track, + handle_list) + self._add_tab(notebook, self.backref_list) + + self._setup_notebook_tabs(notebook) notebook.show_all() self.top.get_widget('vbox').pack_start(notebook, True) + self.track_ref_for_deletion("source_list") + self.track_ref_for_deletion("note_list") + self.track_ref_for_deletion("gallery_list") + self.track_ref_for_deletion("attr_list") + self.track_ref_for_deletion("backref_list") + def _cleanup_on_exit(self): - self.backref_tab.close() + self.backref_list.close() def build_menu_names(self, event): return (_('Edit Event'), self.get_menu_title()) diff --git a/src/ManagedWindow.py b/src/ManagedWindow.py index c36b7f68d..9a0792945 100644 --- a/src/ManagedWindow.py +++ b/src/ManagedWindow.py @@ -2,7 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2006 Donald N. Allingham -# 2009 Gary Burton +# Copyright (C) 2009 Gary Burton # # 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 @@ -334,6 +334,7 @@ class ManagedWindow: self.isWindow = None self.width_key = None self.height_key = None + self.__refs_for_deletion = [] if uistate.gwm.get_item_from_id(window_key): uistate.gwm.get_item_from_id(window_key).present() @@ -466,6 +467,7 @@ class ManagedWindow: Takes care of closing children and removing itself from menu. """ + self.clean_up() self._save_size() self.uistate.gwm.close_track(self.track) self.opened = False @@ -500,6 +502,26 @@ class ManagedWindow: Config.set(self.width_key, width) Config.set(self.height_key, height) Config.sync() + + def track_ref_for_deletion(self, ref): + """ + Record references of instance variables that need to be removed + from scope so that the class can be garbage collected + """ + if ref not in self.__refs_for_deletion: + self.__refs_for_deletion.append(ref) + + def clean_up(self): + """ + Remove any instance variables from scope which point to non-glade + GTK objects so that the class can be garbage collected. + Run the clean_up method on the object first before removing it. + """ + while len(self.__refs_for_deletion): + attr = self.__refs_for_deletion.pop() + obj = getattr(self, attr) + obj.clean_up() + delattr(self, attr) #------------------------------------------------------------------------- # # Helper functions