Split selections.py into three different controller classes, one for each list. There

is still some work to be done, and bugs to be fixed.
This commit is contained in:
Einar Ryeng 2007-02-21 00:00:26 +00:00
parent a2195bcb4b
commit 2cc4e86b0a
2 changed files with 329 additions and 211 deletions

View File

@ -152,9 +152,12 @@ class FluentApp:
gtk.glade.set_custom_handler(self.custom_object_factory)
self.widget_tree = gtk.glade.XML(GLADEFILENAME, 'appwindow')
self.workflow = wf(self)
self.dimlistcontroller = selections.DimListController(self['dim_list'],
self['selection_tree'],
self['identifier_list'])
self.idlist_crt = selections.IdListController(self['identifier_list'])
self.sellist_crt = selections.SelectionListController(self['selection_tree'],
self.idlist_crt)
self.dimlist_crt = selections.DimListController(self['dim_list'],
self.sellist_crt)
def init_gui(self):
self['appwindow'].set_size_request(800, 600)
@ -203,7 +206,7 @@ class FluentApp:
project.project = proj
self.workflow.add_project(proj)
self.navigator_view.add_project(proj)
self.dimlistcontroller.set_project(proj)
self.dimlist_crt.set_project(proj)
def set_workflow(self, workflow):
self.workflow = workflow

View File

@ -21,244 +21,126 @@ class SimpleMenu(gtk.Menu):
item.show()
class DimListController:
def __init__(self, dimlist, seltree, idlist):
class IdListController:
"""Controller class for the identifier list."""
def __init__(self, idlist):
self._idlist = idlist
# dimname: current_annotation_name
self._annotation = {}
# current dimension
self._dimension = None
# id, annotation
self._idstore = gtk.ListStore(gobject.TYPE_STRING,
gobject.TYPE_STRING,)
self._current_dim = None
## dimstore is a list of all dimensions in the application
self.dimstore = gtk.ListStore(gobject.TYPE_STRING)
## Two types of lines, one for CategoryDatasets and one for
## Selections. The elements are title, link to dataset or selection
## and the name of the dimension.
self.selstore = gtk.TreeStore(gobject.TYPE_STRING,
gobject.TYPE_PYOBJECT,
gobject.TYPE_STRING)
self.selstore_filter = self.selstore.filter_new()
self.selstore_filter.set_visible_func(self.dimension_filter)
## idstore is a list of currently selected identifiers
## the list is cleared and rebuilt each time a new selection is
## focused.
self.idstore = gtk.ListStore(gobject.TYPE_STRING)
## The widgets we are controlling
self.dimlist = dimlist
self.seltree = seltree
self.idlist = idlist
## Set up dimensions list
dimlist.set_model(self.dimstore)
renderer = gtk.CellRendererText()
dim_column = gtk.TreeViewColumn('Dimension', renderer, text=0)
dimlist.insert_column(dim_column, 0)
dimlist.connect('row-activated', self._dim_row_activated)
dimlist.connect('cursor-changed', self._dim_cursor_changed)
## Set up selection tree
seltree.set_model(self.selstore_filter)
renderer = gtk.CellRendererText()
sel_column = gtk.TreeViewColumn('Selection', renderer, text=0)
seltree.insert_column(sel_column, 0)
seltree.connect('row-activated', self._sel_row_activated)
seltree.connect('cursor-changed', self._sel_cursor_changed)
seltree.drag_dest_set(gtk.DEST_DEFAULT_ALL,
[("GTK_TREE_MODEL_ROW", gtk.TARGET_SAME_APP, 7)],
gtk.gdk.ACTION_LINK)
seltree.connect('drag-data-received', self._drag_data_received)
## Set up identifier list
idlist.set_model(self.idstore)
idlist.set_model(self._idstore)
renderer = gtk.CellRendererText()
dim_column = gtk.TreeViewColumn('Identifiers', renderer, text=0)
idlist.insert_column(dim_column, 0)
idlist.connect('button-press-event', self._idlist_button_pressed)
idlist.connect('button-press-event', self._button_pressed)
## Set up identifier list context menu
self._idlist_menu = SimpleMenu()
self._idlist_menu.add_simple_item('Import...', self._on_idlist_import)
self._idlist_menu.add_simple_item('Export...', self._on_idlist_export)
menu = self._menu = SimpleMenu()
menu.add_simple_item('Import...', self._on_import_list)
menu.add_simple_item('Export...', self._on_export_list)
i = gtk.MenuItem('Show annotations')
self._idlist_menu.append(i)
i.show()
self._idlist_menu_ann = i
def get_dataset_iter(self, dataset):
"""Returns the iterator to the selection tree row containing a
given dataset."""
i = self.selstore.get_iter_first()
while i:
if self.selstore.get_value(i, 1) == dataset:
return i
i = self.selstore.iter_next(i)
return None
def get_current_selection_iter(self, selection, dimension):
i = self.selstore.get_iter_first()
while i:
if self.selstore.get_value(i, 1) == selection:
if self.selstore.get_value(i, 2) == dimension:
return i
i = self.selstore.iter_next(i)
return None
def set_project(self, project):
"""Dependency injection."""
self.project = project
self.dim_names = project.dim_names
self.update_dims()
project.add_selection_observer(self)
project.add_dataset_observer(self)
def get_dimension(self, dim):
"""Returns the iterator to the dimension with the given name, or
None if not found."""
i = self.dimstore.get_iter_first()
while i:
if self.dimstore.get_value(i, 0) == dim:
return i
i = self.dimstore.iter_next(i)
return None
def dimension_filter(self, store, row):
"""Filters out everything but the selected dimension."""
row_dim = store.get_value(row, 2)
return row_dim == self._current_dim
def update_dims(self):
"""Update the list of dimensions shown"""
for dim in self.dim_names:
if not self.get_dimension(dim):
self.dimstore.insert_after(None, (dim,))
def add_dataset(self, dataset):
di = self.get_dataset_iter(dataset)
if not di:
values = (dataset.get_name(), dataset, dataset.get_dim_name(0))
i = self.selstore.insert_after(None, None, values)
for selection in dataset.as_selections():
values = (selection.title, selection, dataset.get_dim_name(0))
self.selstore.insert_after(i, None, values)
def selection_changed(self, dim_name, selection):
"""Callback function from Project."""
for dim in selection.dims():
if not self.get_current_selection_iter(selection, dim):
values = (selection.title, selection, dim)
self.selstore.insert_after(None, None, values)
self.update_dims()
def dataset_changed(self):
"""Callback function from Project."""
self.update_dims()
## GTK Callbacks.
def _dim_cursor_changed(self, widget):
cursor = self.dimlist.get_cursor()[0]
i = self.dimstore.get_iter(cursor)
row = self.dimstore.get_value(i, 0)
self.set_dimension(row)
def _dim_row_activated(self, widget, path, column):
self.seltree.grab_focus()
def _sel_cursor_changed(self, widget):
"Show the list of identifier strings."
p = self.seltree.get_cursor()[0]
p = self.selstore_filter.convert_path_to_child_path(p)
i = self.selstore.get_iter(p)
obj = self.selstore.get_value(i, 1)
id_list = []
if isinstance(obj, dataset.Selection):
id_list = list(obj[self._current_dim])
id_list.sort()
self.idstore.clear()
for e in id_list:
self.idstore.append((e,))
def _sel_row_activated(self, widget, path, column):
path = self.selstore_filter.convert_path_to_child_path(path)
i = self.selstore.get_iter(path)
obj = self.selstore.get_value(i, 1)
if isinstance(obj, dataset.Dataset):
seltree = self.seltree
if seltree.row_expanded(path):
seltree.collapse_row(path)
else:
seltree.expand_row(path, True)
elif isinstance(obj, dataset.Selection):
self.project.set_selection(self._current_dim,
obj[self._current_dim])
item = gtk.MenuItem('Show annotations')
menu.append(item)
item.show()
self._menu_ann = item
##
## Public interface
##
def set_dimension(self, dimname):
self._current_dim = dimname
self.selstore_filter.refilter()
"""Set dimension"""
if dimname == self._dimension:
return
dim = self.get_dimension(self._current_dim)
path = self.dimstore.get_path(dim)
if not self._annotation.has_key(dimname):
self._annotation[dimname] = None
self._dimension = dimname
def set_annotation(self, annotation):
"""Set the displayed annotation to annotation.
If annotation is None, the annotation column is hidden. Otherwise the annotation
column is shown and filled with values from the given annotation field."""
if annotation == self._annotation:
return
if self.dimlist.get_cursor()[0] != path:
self.dimlist.set_cursor(self.dimstore.get_path(dim))
if self.annotation == None:
self._idlist.remove_column(self._annotation_colum)
else:
for x in self._idstore:
print "set annotation:", x
def _drag_data_received(self, widget, drag_context, x, y,
selection, info, timestamp):
treestore, path = selection.tree_get_row_drag_data()
i = treestore.get_iter(path)
obj = treestore.get_value(i, 2)
if isinstance(obj, dataset.CategoryDataset):
self.add_dataset(obj)
self.set_dimension(obj.get_dim_name(0))
widget.emit_stop_by_name('drag-data-received')
def set_selection(self, selection):
"""Set the selection to be displayed.
The selection is not stored, the values are copied into the TreeStore"""
self._idstore.clear()
id_list = list(selection[self._dimension])
idlist = list(selection[self._dimension])
if self._annotation[self._dimension] != None:
annlist = annotations.get_dim_annotations(self._dimension,
self._annotation[self._dimension],
idlist)
for id, ann in zip(idlist, annlist):
self._idstore.append((id, ann))
else:
for e in idlist:
self._idstore.append((e, None))
##
## Private interface
##
def _update_annotations_menu(self):
dim_h = annotations.get_dim_handler(self._current_dim)
"""Updates the annotations menu with the available annotations for the
current dim."""
dim_h = annotations.get_dim_handler(self._dimension)
if not dim_h:
print "No annotations etc"
self._idlist_menu_ann.set_sensitive(False)
self._menu_ann.set_sensitive(False)
else:
annotations_menu = gtk.Menu()
self._idlist_menu_ann.set_sensitive(True)
ann_names = annotations.get_dim_handler(self._current_dim).get_annotation_names()
self._menu_ann.set_sensitive(True)
ann_names = annotations.get_dim_handler(self._dimension).get_annotation_names()
for ann in ann_names:
item = gtk.MenuItem(ann)
item.connect('activate', self._on_annotation_activated, ann)
annotations_menu.append(item)
item.show()
self._idlist_menu_ann.set_submenu(annotations_menu)
self._menu_ann.set_submenu(annotations_menu)
def _idlist_button_pressed(self, widget, event):
if event.button == 3:
self._update_annotations_menu()
self._idlist_menu.popup(None, None, None, event.button, event.time)
def _popup_idlist_menu(self, *rest):
##
## GTK Callbacks
##
def _popup_menu(self, *rest):
self._update_annotations_menu()
self._idlist_menu.popup(None, None, None, 0, 0)
self._menu.popup(None, None, None, 0, 0)
def _on_annotation_activated(self, menuitem, annotation):
print "Congratulations. You chouse %s" % annotation
self.set_annotation(annotation)
def _on_idlist_export(self, menuitem):
def _button_pressed(self, widget, event):
if event.button == 3:
self._update_annotations_menu()
self._menu.popup(None, None, None, event.button, event.time)
def _on_export_list(self, menuitem):
print "export stuff"
def _on_idlist_import(self, menuitem):
def _on_import_list(self, menuitem):
dialog = gtk.FileChooserDialog('Load annotations')
dialog.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
@ -274,5 +156,238 @@ class DimListController:
print "unknown; ", retval
dialog.destroy()
pass
class SelectionListController:
def __init__(self, seltree, idlist_controller):
self._seltree = seltree
self._sel_stores = {}
self._dimension = None
self._idlist_controller = idlist_controller
renderer = gtk.CellRendererText()
sel_column = gtk.TreeViewColumn('Selection', renderer, text=0)
seltree.insert_column(sel_column, 0)
seltree.connect('row-activated', self._on_row_activated)
seltree.connect('cursor-changed', self._on_cursor_changed)
seltree.drag_dest_set(gtk.DEST_DEFAULT_ALL,
[("GTK_TREE_MODEL_ROW", gtk.TARGET_SAME_APP, 7)],
gtk.gdk.ACTION_LINK)
seltree.connect('drag-data-received', self._drag_data_received)
##
## Public interface
##
def set_dimension(self, dim):
print "SelTreeController.set_dimension(%s)" % dim
self._ensure_selection_store(dim)
self._seltree.set_model(self._sel_stores[dim])
self._idlist_controller.set_dimension(dim)
self._dimension = dim
def selection_changed(self, dimname, selection):
"""Callback function from Project."""
print "selection_changed"
for dim in selection.dims():
self._ensure_selection_store(dim)
store = self._sel_stores[dim]
if not self._get_current_selection_iter(selection, dim):
print " inserting into store"
values = (selection.title, selection, dim)
store.insert_after(None, None, values)
def add_dataset(self, dataset):
store = self._sel_stores[dataset.get_dim_name(0)]
di = self._get_dataset_iter(dataset)
if not di:
values = (dataset.get_name(), dataset, dataset.get_dim_name(0))
i = store.insert_after(None, None, values)
for selection in dataset.as_selections():
values = (selection.title, selection, dataset.get_dim_name(0))
store.insert_after(i, None, values)
##
## Private interface
##
def _add_selection_store(self, dim):
"""Add a new gtk.TreeStore for the selections on a dimension."""
# Create new store
## Two types of lines, one for CategoryDatasets and one for
## Selections. The elements are title, link to dataset or selection
## and the name of the dimension.
store = gtk.TreeStore(gobject.TYPE_STRING,
gobject.TYPE_PYOBJECT,
gobject.TYPE_STRING)
# Set selection store for this dimension
self._sel_stores[dim] = store
def _ensure_selection_store(self, dim):
"""Ensure that the object has a gtk.TreeStore for the given dimension"""
# Do not overwrite existing stores
if self._sel_stores.has_key(dim):
return
self._add_selection_store(dim)
def _get_dataset_iter(self, ds):
"""Returns the iterator to the selection tree row containing a
given dataset."""
store = self._sel_stores[ds.get_dim_name(0)]
i = store.get_iter_first()
while i:
if store.get_value(i, 1) == ds:
return i
i = store.iter_next(i)
return None
def _get_current_selection_iter(self, selection, dimension):
if not self._sel_stores.has_key(dimension):
return None
store = self._sel_stores[dimension]
i = store.get_iter_first()
while i:
if store.get_value(i, 1) == selection:
if store.get_value(i, 2) == dimension:
return i
i = store.iter_next(i)
return None
##
## GTK callbacks
##
def _drag_data_received(self, widget, drag_context, x, y,
selection, info, timestamp):
treestore, path = selection.tree_get_row_drag_data()
i = treestore.get_iter(path)
obj = treestore.get_value(i, 2)
if isinstance(obj, dataset.CategoryDataset):
self.add_dataset(obj)
self.set_dimension(obj.get_dim_name(0))
widget.emit_stop_by_name('drag-data-received')
def _on_cursor_changed(self, widget):
"Show the list of identifier strings."
store = self._sel_stores[self._dimension]
p = self._seltree.get_cursor()[0]
i = store.get_iter(p)
obj = store.get_value(i, 1)
if isinstance(obj, dataset.Selection):
self._idlist_controller.set_selection(obj)
def _on_row_activated(self, widget, path, column):
store = self._sel_stores[self._dimension]
i = store.get_iter(path)
obj = store.get_value(i, 1)
if isinstance(obj, dataset.Dataset):
seltree = self._seltree
if seltree.row_expanded(path):
seltree.collapse_row(path)
else:
seltree.expand_row(path, True)
elif isinstance(obj, dataset.Selection):
self.project.set_selection(self._dimension,
obj[self._dimension])
class DimListController:
def __init__(self, dimlist, seltree_controller):
self._current_dim = None
self._seltree_controller = seltree_controller
## dimstore is a list of all dimensions in the application
self.dimstore = gtk.ListStore(gobject.TYPE_STRING)
## The widgets we are controlling
self.dimlist = dimlist
## Set up dimensions list
dimlist.set_model(self.dimstore)
renderer = gtk.CellRendererText()
dim_column = gtk.TreeViewColumn('Dimension', renderer, text=0)
dimlist.insert_column(dim_column, 0)
dimlist.connect('row-activated', self._dim_row_activated)
dimlist.connect('cursor-changed', self._dim_cursor_changed)
##
## Public interface
##
def set_project(self, project):
"""Dependency injection."""
self.project = project
self.dim_names = project.dim_names
self.update_dims()
project.add_selection_observer(self._seltree_controller)
project.add_dataset_observer(self)
def get_dimension(self, dim):
"""Returns the iterator to the dimension with the given name, or
None if not found."""
i = self.dimstore.get_iter_first()
while i:
if self.dimstore.get_value(i, 0) == dim:
return i
i = self.dimstore.iter_next(i)
return None
def set_dimension(self, dimname):
self._current_dim = dimname
dim = self.get_dimension(self._current_dim)
path = self.dimstore.get_path(dim)
if self.dimlist.get_cursor()[0] != path:
self.dimlist.set_cursor(self.dimstore.get_path(dim))
self._seltree_controller.set_dimension(dimname)
print "DimListController.set_dimension()"
def dataset_changed(self):
"""Callback function from Project."""
self.update_dims()
##
## Private interface
##
def update_dims(self):
"""Update the list of dimensions shown"""
for dim in self.dim_names:
if not self.get_dimension(dim):
self.dimstore.insert_after(None, (dim,))
def _dimension_filter(self, store, row):
"""Filters out everything but the selected dimension."""
row_dim = store.get_value(row, 2)
return row_dim == self._current_dim
##
## GTK Callbacks.
##
def _dim_cursor_changed(self, widget):
cursor = self.dimlist.get_cursor()[0]
i = self.dimstore.get_iter(cursor)
row = self.dimstore.get_value(i, 0)
self.set_dimension(row)
def _dim_row_activated(self, widget, path, column):
self._seltree_controller.set_dimension(dim)