from system import logger, dataset import pygtk import gtk import gtk.gdk import gtk.glade import gnome import gnome.ui import gobject class SimpleMenu(gtk.Menu): def __init__(self): gtk.Menu.__init__(self) def add_simple_item(self, title, function): item = gtk.MenuItem(title) item.connect('activate', function) self.append(item) item.show() class DimListController: def __init__(self, dimlist, seltree, idlist): 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) renderer = gtk.CellRendererText() dim_column = gtk.TreeViewColumn('Identifiers', renderer, text=0) idlist.insert_column(dim_column, 0) 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]) def set_dimension(self, dimname): self._current_dim = dimname self.selstore_filter.refilter() 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)) 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')