diff --git a/gramps2/ChangeLog b/gramps2/ChangeLog index c91386277..31f1e8ce8 100644 --- a/gramps2/ChangeLog +++ b/gramps2/ChangeLog @@ -1,4 +1,11 @@ 2006-03-31 Don Allingham + * src/ManagedWindow.py: added + * src/DisplayState.py: break out managed window stuff + * src/Editors/_EditPrimary.py: use ManagedWindow + * src/Editors/_EditSecondary.py: use ManagedWindow + * src/Editors/_EditReference.py: use ManagedWindow + * src/ObjectSelector/_ObjectSelectorWindow.py: use ManagedWindow + * src/PluginUtils/_Plugins.py: use ManagedWindow * src/GrampsDb/_GrampsDbBase.py: handle saving of custom attributes and event types for use in menus * src/Editors/_EditAttribute.py: support for family vs. person diff --git a/gramps2/src/DisplayState.py b/gramps2/src/DisplayState.py index cddc21fdd..6f56865b2 100644 --- a/gramps2/src/DisplayState.py +++ b/gramps2/src/DisplayState.py @@ -51,9 +51,10 @@ import gtk import GrampsDb import Config import NameDisplay -import Mime import const -import Errors +import ManagedWindow + +DISABLED = -1 #------------------------------------------------------------------------- # @@ -135,221 +136,6 @@ class History(GrampsDb.GrampsDBCallback): if not self.at_end(): self.history = self.history[0:self.index+1] -#------------------------------------------------------------------------- -# -# Window manager -# -#------------------------------------------------------------------------- - -_win_top = '' -_win_btm = '' -DISABLED = -1 - -class GrampsWindowManager: - """ - Manage hierarchy of open GRAMPS windows. - - This class's purpose is to manage the hierarchy of open windows. - The idea is to maintain the tree of branches and leaves. - A leaf does not have children and corresponds to a single open window. - A branch has children and corresponds to a group of windows. - - We will follow the convention of having first leaf in any given - branch represent a parent window of the group, and the rest of the - children leaves/branches represent windows spawned from the parent. - - The tree structure is maintained as a list of items. - Items which are lists are branches. - Items which are not lists are leaves. - - Lookup of an item is done via track sequence. The elements of - the track sequence specify the lookup order: [2,3,1] means - 'take the second item of the tree, take its third child, and - then the first child of that child'. - - Lookup can be also done by ID for windows that are identifiable. - """ - - def __init__(self,uimanager): - # initialize empty tree and lookup dictionary - self.uimanager = uimanager - self.window_tree = [] - self.id2item = {} - self.action_group = gtk.ActionGroup('WindowManger') - self.active = DISABLED - self.ui = _win_top + _win_btm - - def disable(self): - """ - Removes the UI and action groups if the navigation is enabled - """ - if self.active != DISABLED: - self.uimanager.remove_ui(self.active) - self.uimanager.remove_action_group(self.action_group) - self.active = DISABLED - - def enable(self): - """ - Enables the UI and action groups - """ - self.uimanager.insert_action_group(self.action_group, 1) - self.active = self.uimanager.add_ui_from_string(self.ui) - - def get_item_from_track(self,track): - # Recursively find an item given track sequence - item = self.window_tree - for index in track: - item = item[index] - return item - - def get_item_from_id(self,item_id): - # Find an item given its ID - # Return None if the ID is not found - return self.id2item.get(item_id,None) - - def close_track(self,track): - # This is called when item needs to be closed - # Closes all its children and then removes the item from the tree. - item = self.get_item_from_track(track) - self.recursive_action(item,self.close_item) - # This only needs to be run once for the highest level point - # to remove. - self.remove_item(track) - - def recursive_action(self,item,func,*args): - # This function recursively calls itself over the child items - # starting with the given item. - # Eventualy, every non-list item (leaf) will be reached - # and the func(item,*args) will be called on that item. - if type(item) == list: - # If this item is a branch - # close the children except for the first one - for sub_item in item[1:]: - self.recursive_action(sub_item,func,*args) - # return the first child - last_item = item[0] - else: - # This item is a leaf -- no children to close - # return itself - last_item = item - func(last_item,*args) - - def close_item(self,item,*args): - # Given an item, close its window and remove it's ID from the dict - if item.window_id: - del self.id2item[item.window_id] - if item.window: - item.window.destroy() - - def remove_item(self,track): - # We need the whole gymnastics below because our item - # may actually be a list consisting of a single real - # item and empty lists. - - # find the track corresponding to the parent item - parent_track = track[:-1] - # find index of our item in parent - child_in_parent = track[-1:][0] - # obtain parent item and remove our item from it - parent_item = self.get_item_from_track(parent_track) - parent_item.pop(child_in_parent) - # Adjust each item following the removed one - # so that it's track is down by one on this level - for ix in range(child_in_parent,len(parent_item)): - item = parent_item[ix] - self.recursive_action(item,self.move_item_down,len(track)-1) - # Rebuild menu - self.build_windows_menu() - - def move_item_down(self,item,*args): - # Given an item and an index, adjust the item's track - # by subtracting 1 from that index's level - index = args[0] - item.track[index] -= 1 - - def add_item(self,track,item): - # if the item is identifiable then we need to remember - # its id so that in the future we recall this window - # instead of spawning a new one - if item.window_id: - self.id2item[item.window_id] = item - - # Make sure we have a track - parent_item = self.get_item_from_track(track) - assert type(parent_item) == list or track == [], \ - "Gwm: add_item: Incorrect track." - - # Prepare a new item, depending on whether it is branch or leaf - if item.submenu_label: - # This is an item with potential children -- branch - new_item = [item] - else: - # This is an item without children -- leaf - new_item = item - - # append new item to the parent - parent_item.append(new_item) - - # rebuild the Windows menu based on the new tree - self.build_windows_menu() - - # prepare new track corresponding to the added item and return it - new_track = track + [len(parent_item)-1] - return new_track - - def call_back_factory(self,item): - if type(item) != list: - def f(obj): - if item.window_id and self.id2item.get(item.window_id): - self.id2item[item.window_id].present() - else: - def f(obj): - pass - return f - - def generate_id(self,item): - return str(item.window_id) - - def display_menu_list(self,data,action_data,mlist): - i = mlist[0] - idval = self.generate_id(i) - data.write('' % idval) - data.write('' % idval) - - action_data.append(("M:"+idval,None,i.submenu_label,None,None,None)) - action_data.append((idval,None,i.menu_label,None,None, - self.call_back_factory(i))) - - if len(mlist) > 1: - for i in mlist[1:]: - if type(i) == list: - self.display_menu_list(data,action_data,i) - else: - idval = self.generate_id(i) - data.write('' - % self.generate_id(i)) - action_data.append((idval,None,i.menu_label,None,None, - self.call_back_factory(i))) - data.write('') - - def build_windows_menu(self): - if self.active != DISABLED: - self.uimanager.remove_ui(self.active) - self.uimanager.remove_action_group(self.action_group) - - self.action_group = gtk.ActionGroup('WindowManger') - action_data = [] - - data = StringIO() - data.write(_win_top) - for i in self.window_tree: - self.display_menu_list(data,action_data,i) - data.write(_win_btm) - self.ui = data.getvalue() - data.close() - self.action_group.add_actions(action_data) - self.enable() - #------------------------------------------------------------------------- # @@ -404,7 +190,6 @@ class RecentDocsMenu: for item in rfiles: try: filename = os.path.basename(item.get_path()).replace('_','__') - filetype = Mime.get_type(item.get_path()) action_id = "RecentMenu%d" % count f.write('' % action_id) actions.append((action_id,None,filename,None,None, @@ -428,102 +213,6 @@ def make_callback(n,f): def by_time(a,b): return cmp(b.get_time(),a.get_time()) -#------------------------------------------------------------------------- -# -# Gramps Managed Window class -# -#------------------------------------------------------------------------- -class ManagedWindow: - """ - Managed window base class. - - This class provides all the goodies necessary for user-friendly window - management in GRAMPS: registering the menu item under the Windows - menu, keeping track of child windows, closing them on close/delete - event, and presenting itself when selected or attempted to create again. - """ - - def __init__(self,uistate,track,obj): - """ - Create child windows and add itself to menu, if not there already. - - - The usage from derived classes is envisioned as follows: - - - import DisplayState - class SomeWindowClass(DisplayState.ManagedWindow): - def __init__(self,uistate,dbstate,track): - window_id = self # Or e.g. window_id = person.handle - submenu_label = None # This window cannot have children - menu_label = 'Menu label for this window' - DisplayState.ManagedWindow.__init__(self, - uistate, - track, - window_id, - submenu_label, - menu_label) - # Proceed with the class. - ... - - """ - - window_key = self.build_window_key(obj) - menu_label,submenu_label = self.build_menu_names(obj) - - if uistate.gwm.get_item_from_id(window_key): - uistate.gwm.get_item_from_id(window_key).present() - raise Errors.WindowActiveError('This window is already active') - else: - self.window_id = window_key - self.submenu_label = submenu_label - self.menu_label = menu_label - self.uistate = uistate - self.track = self.uistate.gwm.add_item(track,self) - # Work out parent_window - if len(self.track) > 1: - # We don't belong to the lop level - if self.track[-1] > 0: - # If we are not the first in the group, - # then first in that same group is our parent - parent_item_track = self.track[:-1] - parent_item_track.append(0) - else: - # If we're first in the group, then our parent - # is the first in the group one level up - parent_item_track = self.track[:-2] - parent_item_track.append(0) - - # Based on the track, get item and then window object - self.parent_window = self.uistate.gwm.get_item_from_track( - parent_item_track).window - else: - # On the top level: we use gramps top window - self.parent_window = self.uistate.window - - def build_menu_names(self,obj): - return ('Undefined Menu','Undefined Submenu') - - def build_window_key(self,obj): - return id(self) - - def show(self): - self.window.set_transient_for(self.parent_window) - self.window.show() - - def close(self,obj=None,obj2=None): - """ - Close itself. - - Takes care of closing children and removing itself from menu. - """ - self.uistate.gwm.close_track(self.track) - - def present(self): - """ - Present window (unroll/unminimize/bring to top). - """ - self.window.present() from GrampsLogger import RotateHandler @@ -574,7 +263,7 @@ class DisplayState(GrampsDb.GrampsDBCallback): self.status_id = status.get_context_id('GRAMPS') self.progress = progress self.phistory = History() - self.gwm = GrampsWindowManager(uimanager) + self.gwm = ManagedWindow.GrampsWindowManager(uimanager) self.widget = None self.warnbtn = warnbtn diff --git a/gramps2/src/Editors/_EditPrimary.py b/gramps2/src/Editors/_EditPrimary.py index a4b6ac720..7146bc9e0 100644 --- a/gramps2/src/Editors/_EditPrimary.py +++ b/gramps2/src/Editors/_EditPrimary.py @@ -22,7 +22,7 @@ from TransUtils import sgettext as _ -import DisplayState +import ManagedWindow import DateHandler import NameDisplay import Config @@ -31,7 +31,7 @@ import Utils from QuestionDialog import SaveDialog -class EditPrimary(DisplayState.ManagedWindow): +class EditPrimary(ManagedWindow.ManagedWindow): def __init__(self, state, uistate, track, obj, get_from_handle, callback=None): """Creates an edit window. Associates a person with the window.""" @@ -47,7 +47,7 @@ class EditPrimary(DisplayState.ManagedWindow): self.signal_keys = [] self.get_from_handle = get_from_handle - DisplayState.ManagedWindow.__init__(self, uistate, track, obj) + ManagedWindow.ManagedWindow.__init__(self, uistate, track, obj) self._local_init() diff --git a/gramps2/src/Editors/_EditReference.py b/gramps2/src/Editors/_EditReference.py index e30252d0f..84ec8d57f 100644 --- a/gramps2/src/Editors/_EditReference.py +++ b/gramps2/src/Editors/_EditReference.py @@ -48,7 +48,7 @@ import gtk.glade import const import Utils import RelLib -import DisplayState +import ManagedWindow from QuestionDialog import WarningDialog, ErrorDialog from DisplayTabs import * @@ -59,7 +59,7 @@ from GrampsWidgets import * # EditReference class # #------------------------------------------------------------------------- -class EditReference(DisplayState.ManagedWindow): +class EditReference(ManagedWindow.ManagedWindow): def __init__(self, state, uistate, track, source, source_ref, update): self.db = state.db self.dbstate = state @@ -71,7 +71,7 @@ class EditReference(DisplayState.ManagedWindow): self.signal_keys = [] self.warn_box = None - DisplayState.ManagedWindow.__init__(self, uistate, track, source_ref) + ManagedWindow.ManagedWindow.__init__(self, uistate, track, source_ref) self._local_init() self._setup_warnbox() diff --git a/gramps2/src/Editors/_EditSecondary.py b/gramps2/src/Editors/_EditSecondary.py index 797feedf2..7d292a463 100644 --- a/gramps2/src/Editors/_EditSecondary.py +++ b/gramps2/src/Editors/_EditSecondary.py @@ -22,12 +22,12 @@ from TransUtils import sgettext as _ -import DisplayState +import ManagedWindow import Config import GrampsDisplay import Utils -class EditSecondary(DisplayState.ManagedWindow): +class EditSecondary(ManagedWindow.ManagedWindow): def __init__(self, state, uistate, track, obj, callback=None): """Creates an edit window. Associates a person with the window.""" @@ -39,7 +39,7 @@ class EditSecondary(DisplayState.ManagedWindow): self.callback = callback self.signal_keys = [] - DisplayState.ManagedWindow.__init__(self, uistate, track, obj) + ManagedWindow.ManagedWindow.__init__(self, uistate, track, obj) self._local_init() diff --git a/gramps2/src/ManagedWindow.py b/gramps2/src/ManagedWindow.py new file mode 100644 index 000000000..56d7828df --- /dev/null +++ b/gramps2/src/ManagedWindow.py @@ -0,0 +1,337 @@ +# +# 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: DisplayState.py 6085 2006-03-05 23:39:20Z dallingham $ + +import Errors +import gtk +from cStringIO import StringIO + +#------------------------------------------------------------------------- +# +# Window manager +# +#------------------------------------------------------------------------- + +_win_top = '' +_win_btm = '' +DISABLED = -1 + +class GrampsWindowManager: + """ + Manage hierarchy of open GRAMPS windows. + + This class's purpose is to manage the hierarchy of open windows. + The idea is to maintain the tree of branches and leaves. + A leaf does not have children and corresponds to a single open window. + A branch has children and corresponds to a group of windows. + + We will follow the convention of having first leaf in any given + branch represent a parent window of the group, and the rest of the + children leaves/branches represent windows spawned from the parent. + + The tree structure is maintained as a list of items. + Items which are lists are branches. + Items which are not lists are leaves. + + Lookup of an item is done via track sequence. The elements of + the track sequence specify the lookup order: [2,3,1] means + 'take the second item of the tree, take its third child, and + then the first child of that child'. + + Lookup can be also done by ID for windows that are identifiable. + """ + + def __init__(self,uimanager): + # initialize empty tree and lookup dictionary + self.uimanager = uimanager + self.window_tree = [] + self.id2item = {} + self.action_group = gtk.ActionGroup('WindowManger') + self.active = DISABLED + self.ui = _win_top + _win_btm + + def disable(self): + """ + Removes the UI and action groups if the navigation is enabled + """ + if self.active != DISABLED: + self.uimanager.remove_ui(self.active) + self.uimanager.remove_action_group(self.action_group) + self.active = DISABLED + + def enable(self): + """ + Enables the UI and action groups + """ + self.uimanager.insert_action_group(self.action_group, 1) + self.active = self.uimanager.add_ui_from_string(self.ui) + + def get_item_from_track(self,track): + # Recursively find an item given track sequence + item = self.window_tree + for index in track: + item = item[index] + return item + + def get_item_from_id(self,item_id): + # Find an item given its ID + # Return None if the ID is not found + return self.id2item.get(item_id,None) + + def close_track(self,track): + # This is called when item needs to be closed + # Closes all its children and then removes the item from the tree. + item = self.get_item_from_track(track) + self.recursive_action(item,self.close_item) + # This only needs to be run once for the highest level point + # to remove. + self.remove_item(track) + + def recursive_action(self,item,func,*args): + # This function recursively calls itself over the child items + # starting with the given item. + # Eventualy, every non-list item (leaf) will be reached + # and the func(item,*args) will be called on that item. + if type(item) == list: + # If this item is a branch + # close the children except for the first one + for sub_item in item[1:]: + self.recursive_action(sub_item,func,*args) + # return the first child + last_item = item[0] + else: + # This item is a leaf -- no children to close + # return itself + last_item = item + func(last_item,*args) + + def close_item(self,item,*args): + # Given an item, close its window and remove it's ID from the dict + if item.window_id: + del self.id2item[item.window_id] + if item.window: + item.window.destroy() + + def remove_item(self,track): + # We need the whole gymnastics below because our item + # may actually be a list consisting of a single real + # item and empty lists. + + # find the track corresponding to the parent item + parent_track = track[:-1] + # find index of our item in parent + child_in_parent = track[-1:][0] + # obtain parent item and remove our item from it + parent_item = self.get_item_from_track(parent_track) + parent_item.pop(child_in_parent) + # Adjust each item following the removed one + # so that it's track is down by one on this level + for ix in range(child_in_parent,len(parent_item)): + item = parent_item[ix] + self.recursive_action(item,self.move_item_down,len(track)-1) + # Rebuild menu + self.build_windows_menu() + + def move_item_down(self,item,*args): + # Given an item and an index, adjust the item's track + # by subtracting 1 from that index's level + index = args[0] + item.track[index] -= 1 + + def add_item(self,track,item): + # if the item is identifiable then we need to remember + # its id so that in the future we recall this window + # instead of spawning a new one + if item.window_id: + self.id2item[item.window_id] = item + + # Make sure we have a track + parent_item = self.get_item_from_track(track) + assert type(parent_item) == list or track == [], \ + "Gwm: add_item: Incorrect track." + + # Prepare a new item, depending on whether it is branch or leaf + if item.submenu_label: + # This is an item with potential children -- branch + new_item = [item] + else: + # This is an item without children -- leaf + new_item = item + + # append new item to the parent + parent_item.append(new_item) + + # rebuild the Windows menu based on the new tree + self.build_windows_menu() + + # prepare new track corresponding to the added item and return it + new_track = track + [len(parent_item)-1] + return new_track + + def call_back_factory(self,item): + if type(item) != list: + def f(obj): + if item.window_id and self.id2item.get(item.window_id): + self.id2item[item.window_id].present() + else: + def f(obj): + pass + return f + + def generate_id(self,item): + return str(item.window_id) + + def display_menu_list(self,data,action_data,mlist): + i = mlist[0] + idval = self.generate_id(i) + data.write('' % idval) + data.write('' % idval) + + action_data.append(("M:"+idval,None,i.submenu_label,None,None,None)) + action_data.append((idval,None,i.menu_label,None,None, + self.call_back_factory(i))) + + if len(mlist) > 1: + for i in mlist[1:]: + if type(i) == list: + self.display_menu_list(data,action_data,i) + else: + idval = self.generate_id(i) + data.write('' + % self.generate_id(i)) + action_data.append((idval,None,i.menu_label,None,None, + self.call_back_factory(i))) + data.write('') + + def build_windows_menu(self): + if self.active != DISABLED: + self.uimanager.remove_ui(self.active) + self.uimanager.remove_action_group(self.action_group) + + self.action_group = gtk.ActionGroup('WindowManger') + action_data = [] + + data = StringIO() + data.write(_win_top) + for i in self.window_tree: + self.display_menu_list(data,action_data,i) + data.write(_win_btm) + self.ui = data.getvalue() + data.close() + self.action_group.add_actions(action_data) + self.enable() + +#------------------------------------------------------------------------- +# +# Gramps Managed Window class +# +#------------------------------------------------------------------------- +class ManagedWindow: + """ + Managed window base class. + + This class provides all the goodies necessary for user-friendly window + management in GRAMPS: registering the menu item under the Windows + menu, keeping track of child windows, closing them on close/delete + event, and presenting itself when selected or attempted to create again. + """ + + def __init__(self,uistate,track,obj): + """ + Create child windows and add itself to menu, if not there already. + + + The usage from derived classes is envisioned as follows: + + + import ManagedWindow + class SomeWindowClass(ManagedWindow.ManagedWindow): + def __init__(self,uistate,dbstate,track): + window_id = self # Or e.g. window_id = person.handle + submenu_label = None # This window cannot have children + menu_label = 'Menu label for this window' + ManagedWindow.ManagedWindow.__init__(self, + uistate, + track, + window_id, + submenu_label, + menu_label) + # Proceed with the class. + ... + + """ + + window_key = self.build_window_key(obj) + menu_label,submenu_label = self.build_menu_names(obj) + + if uistate.gwm.get_item_from_id(window_key): + uistate.gwm.get_item_from_id(window_key).present() + raise Errors.WindowActiveError('This window is already active') + else: + self.window_id = window_key + self.submenu_label = submenu_label + self.menu_label = menu_label + self.uistate = uistate + self.track = self.uistate.gwm.add_item(track,self) + # Work out parent_window + if len(self.track) > 1: + # We don't belong to the lop level + if self.track[-1] > 0: + # If we are not the first in the group, + # then first in that same group is our parent + parent_item_track = self.track[:-1] + parent_item_track.append(0) + else: + # If we're first in the group, then our parent + # is the first in the group one level up + parent_item_track = self.track[:-2] + parent_item_track.append(0) + + # Based on the track, get item and then window object + self.parent_window = self.uistate.gwm.get_item_from_track( + parent_item_track).window + else: + # On the top level: we use gramps top window + self.parent_window = self.uistate.window + + def build_menu_names(self,obj): + return ('Undefined Menu','Undefined Submenu') + + def build_window_key(self,obj): + return id(self) + + def show(self): + self.window.set_transient_for(self.parent_window) + self.window.show() + + def close(self,obj=None,obj2=None): + """ + Close itself. + + Takes care of closing children and removing itself from menu. + """ + self.uistate.gwm.close_track(self.track) + + def present(self): + """ + Present window (unroll/unminimize/bring to top). + """ + self.window.present() diff --git a/gramps2/src/ObjectSelector/_ObjectSelectorWindow.py b/gramps2/src/ObjectSelector/_ObjectSelectorWindow.py index 39579053d..35b4fec49 100644 --- a/gramps2/src/ObjectSelector/_ObjectSelectorWindow.py +++ b/gramps2/src/ObjectSelector/_ObjectSelectorWindow.py @@ -34,7 +34,7 @@ from TransUtils import sgettext as _ import _Factories from _Constants import ObjectTypes -from DisplayState import ManagedWindow +from ManagedWindow import ManagedWindow import const class _ObjectTypeWidgets(object): diff --git a/gramps2/src/PluginUtils/_Plugins.py b/gramps2/src/PluginUtils/_Plugins.py index 0baa3f378..8ad17ef12 100644 --- a/gramps2/src/PluginUtils/_Plugins.py +++ b/gramps2/src/PluginUtils/_Plugins.py @@ -61,7 +61,7 @@ import _Report import _Tool import _PluginMgr import GrampsDisplay -import DisplayState +import ManagedWindow #------------------------------------------------------------------------- # @@ -78,7 +78,7 @@ UNSUPPORTED = _("Unsupported") # #------------------------------------------------------------------------- -class PluginDialog(DisplayState.ManagedWindow): +class PluginDialog(ManagedWindow.ManagedWindow): """Displays the dialog box that allows the user to select the report that is desired.""" @@ -93,7 +93,7 @@ class PluginDialog(DisplayState.ManagedWindow): self.msg = msg self.content = content - DisplayState.ManagedWindow.__init__(self, uistate, [], None) + ManagedWindow.ManagedWindow.__init__(self, uistate, [], None) self.state = state self.uistate = uistate @@ -303,13 +303,13 @@ class ToolPlugins(PluginDialog): # #------------------------------------------------------------------------- -class PluginStatus(DisplayState.ManagedWindow): +class PluginStatus(ManagedWindow.ManagedWindow): """Displays a dialog showing the status of loaded plugins""" def __init__(self,state,uistate,track): import cStringIO - DisplayState.ManagedWindow.__init__(self, uistate, [], None) + ManagedWindow.ManagedWindow.__init__(self, uistate, [], None) self.state = state self.uistate = uistate