* src/DisplayState.py: Correct and add comments.

svn: r5546
This commit is contained in:
Alex Roitman 2005-12-14 04:06:42 +00:00
parent 9dbbf2b512
commit c416e79e3a
2 changed files with 101 additions and 37 deletions

View File

@ -1,3 +1,6 @@
2005-12-13 Alex Roitman <shura@gramps-project.org>
* src/DisplayState.py: Correct and add comments.
2005-12-13 Don Allingham <don@gramps-project.org> 2005-12-13 Don Allingham <don@gramps-project.org>
* src/EditPerson.py: fix after merge * src/EditPerson.py: fix after merge
* src/GrampsDbBase.py: fix after merge * src/GrampsDbBase.py: fix after merge

View File

@ -132,61 +132,122 @@ class History(GrampsDBCallback.GrampsDBCallback):
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class GrampsWindowManager: 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): def __init__(self):
# initialize empty tree and lookup dictionary
self.window_tree = [] self.window_tree = []
self.id2item = {} self.id2item = {}
def get_item_from_node(self,node): def get_item_from_track(self,track):
# Recursively find an item given track sequence
item = self.window_tree item = self.window_tree
for index in node: for index in track:
item = item[index] item = item[index]
return item return item
def get_window_from_id(self,window_id): def get_item_from_id(self,item_id):
return self.id2item.get(window_id,None) # Find an item given its ID
# Return None if the ID is not found
return self.id2item.get(item_id,None)
def close_node(self,node): def close_item(self,track):
import traceback # This is called when item needs to be closed
traceback.print_stack() # Closes all its children and then removes the item from the tree.
item = self.get_item_from_node(node) item = self.get_item_from_track(track)
self.close_item_recursively(item) last_item = self.close_item_recursively(item)
self.remove_node(node) # now we have the only surviving item from possibly a huge
# nested group of items
if last_item.window_id:
del self.id2item[last_item.window_id]
last_item.window.destroy()
self.remove_item(track)
def close_item_recursively(self,item): def close_item_recursively(self,item):
# This function calls children's close_item() method
# to let the children go away cleanly. Then it returns
# the actual window item to later remove from dictionary
# and delete.
if type(item) == list: if type(item) == list:
# If this item is a branch
# close the children except for the first one
for sub_item in item[1:]: for sub_item in item[1:]:
self.close_item_recursively(sub_item) self.close_item(sub_item)
# return the first child
the_item = item[0]
else: else:
if item.window_id: # This item is a leaf -- no children to close
del self.id2item[item.window_id] # return itself
item.window.destroy() the_item = item
return the_item
def add_item(self,node,item):
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)
# Rebuild menu
self.build_windows_menu()
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: if item.window_id:
self.id2item[item.window_id] = item self.id2item[item.window_id] = item
parent_item = self.get_item_from_node(node) # Make sure we have a track
assert type(parent_item) == list or node == [], \ parent_item = self.get_item_from_track(track)
"Gwm: add_item: Incorrect node." 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: if item.submenu_label:
# This is an item with potential children # This is an item with potential children -- branch
new_item = [item] new_item = [item]
else: else:
# This is an item without children # This is an item without children -- leaf
new_item = item new_item = item
parent_item.append(new_item)
new_node = node + [len(parent_item) + 1]
self.build_windows_menu()
return new_node
def remove_node(self,node): # append new item to the parent
parent_node = node[:-1] parent_item.append(new_item)
child_in_parent = node[-1:][0]
item = self.get_item_from_node(parent_node) # rebuild the Windows menu based on the new tree
item.pop(child_in_parent)
self.build_windows_menu() 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): def call_back_factory(self,item):
if type(item) != list: if type(item) != list:
def f(obj): def f(obj):
@ -217,7 +278,7 @@ class ManagedWindow:
event, and presenting itself when selected or attempted to create again. event, and presenting itself when selected or attempted to create again.
""" """
def __init__(self,uistate,node,window_key,submenu_label,menu_label): def __init__(self,uistate,track,window_key,submenu_label,menu_label):
""" """
Create child windows and add itself to menu, if not there already. Create child windows and add itself to menu, if not there already.
@ -227,13 +288,13 @@ class ManagedWindow:
import DisplayState import DisplayState
class SomeWindowClass(DisplayState.ManagedWindow): class SomeWindowClass(DisplayState.ManagedWindow):
def __init__(self,uistate,dbstate,node): def __init__(self,uistate,dbstate,track):
window_id = self # Or e.g. window_id = person.handle window_id = self # Or e.g. window_id = person.handle
submenu_label = None # This window cannot have children submenu_label = None # This window cannot have children
menu_label = 'Menu label for this window' menu_label = 'Menu label for this window'
DisplayState.ManagedWindow.__init__(self, DisplayState.ManagedWindow.__init__(self,
uistate, uistate,
node, track,
window_id, window_id,
submenu_label, submenu_label,
menu_label) menu_label)
@ -244,8 +305,8 @@ class ManagedWindow:
... ...
""" """
if uistate.gwm.get_window_from_id(window_key): if uistate.gwm.get_item_from_id(window_key):
uistate.gwm.get_window_from_id(window_key).present() uistate.gwm.get_item_from_id(window_key).present()
self.already_exist = True self.already_exist = True
else: else:
self.already_exist = False self.already_exist = False
@ -253,7 +314,7 @@ class ManagedWindow:
self.submenu_label = submenu_label self.submenu_label = submenu_label
self.menu_label = menu_label self.menu_label = menu_label
self.uistate = uistate self.uistate = uistate
self.node = self.uistate.gwm.add_item(node,self) self.track = self.uistate.gwm.add_item(track,self)
def close(self): def close(self):
""" """
@ -261,7 +322,7 @@ class ManagedWindow:
Takes care of closing children and removing itself from menu. Takes care of closing children and removing itself from menu.
""" """
self.uistate.gwm.close_node(self.node) self.uistate.gwm.close_item(self.track)
def present(self): def present(self):
""" """