diff --git a/system/navigator.py b/system/navigator.py index 9d241ce..e37e2a7 100644 --- a/system/navigator.py +++ b/system/navigator.py @@ -15,34 +15,41 @@ class NavigatorView (gtk.TreeView): gtk.TreeView.__init__(self) + # various properties self.set_headers_visible(False) + + # Selection Mode + self.get_selection().set_mode(gtk.SELECTION_MULTIPLE) + self.get_selection().set_select_function(self.is_selectable) + + # Setting up TextRenderers etc self.connect('cursor_changed', self.cursor_changed_handler) self.connect('row_activated', self.row_activated_handler) - #pixrenderer = gtk.CellRendererPixbuf() textrenderer = gtk.CellRendererText() self.object_col = gtk.TreeViewColumn('Object') - #self.object_col.pack_start(pixrenderer) self.object_col.pack_start(textrenderer) - self.object_col.set_attributes(textrenderer, cell_background=3, foreground = 4, text=0) self.append_column(self.object_col) - # drag'n'drop - self.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,[("GTK_TREE_MODEL_ROW",gtk.TARGET_SAME_APP,7)], gtk.gdk.ACTION_LINK) + # send events to plots / itself + self.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,[("GTK_TREE_MODEL_ROW",gtk.TARGET_SAME_APP,7)], gtk.gdk.ACTION_LINK | gtk.gdk.ACTION_MOVE) + + # receive MOVE drag'n'drops from itself + self.enable_model_drag_dest([("GTK_TREE_MODEL_ROW",gtk.TARGET_SAME_WIDGET,138)],gtk.gdk.ACTION_MOVE) + self.connect("drag-data-get",self.slot_drag_data) logger.log('debug', 'Initializing navigator window.') - + # sets data for drag event. def slot_drag_data(self,treeview,context,selection,target_id,etime): treeselection = treeview.get_selection() - model, iter = treeselection.get_selected() - path = model.get_path(iter) - - self.data_tree.drag_data_get(path, selection) + model, paths = treeselection.get_selected_rows() + if paths: + self.data_tree.drag_data_get(paths[0], selection) def add_project(self, project): @@ -50,18 +57,44 @@ class NavigatorView (gtk.TreeView): self.data_tree = project.data_tree self.set_model(project.data_tree) self.data_tree.connect('row-changed',self.row_changed_handler) + + def is_selectable(self,path): + if self.data_tree: + obj = self.data_tree.get_value(self.data_tree.get_iter(path),2) + if not obj: + return False + if not isinstance(obj, dataset.Dataset): + return False + return True + # selection changed, setting current_data ojbects def cursor_changed_handler(self, widget): - selection = widget.get_selection() - model, tree_iter = selection.get_selected() - obj = self.data_tree.get_value(tree_iter, 2) - if isinstance(obj, dataset.Dataset): + + + selection = widget.get_selection() + model, paths = selection.get_selected_rows() + + objs = [self.data_tree.get_value(self.data_tree.get_iter(path),2) for path in paths] + + if objs and isinstance(objs[0], dataset.Dataset): logger.log('debug', 'Selecting dataset') - self.project.set_current_data(obj) - else: - t = type(obj) - logger.log('debug', 'Selected datatype was %s. Don\'t know what to do.' % t) + self.project.set_current_data(objs) + + + # current object hasn't been added to selection yet, so we're adding it in + cur_path, column = widget.get_cursor() + + obj = model.get_value(model.get_iter(cur_path),2) + objs = [model.get_value(model.get_iter(path), 2) for path in paths] + + if (not obj in objs) and isinstance(obj, dataset.Dataset): + objs += obj + + if objs: + if isinstance(objs[0], dataset.Dataset): + logger.log('debug', 'Selecting dataset') + self.project.set_current_data(objs) # TreeView changed. Set correct focus and colours def row_changed_handler(self, treestore, pos, iter): @@ -75,8 +108,8 @@ class NavigatorView (gtk.TreeView): if isinstance(obj,dataset.Dataset): self.set_cursor(pos) - - + self.grab_focus() + def display_data_info(self, data): dims = zip(data.get_dim_names(), data.shape) diff --git a/system/workflow.py b/system/workflow.py index d38198d..d65b1e7 100644 --- a/system/workflow.py +++ b/system/workflow.py @@ -102,6 +102,7 @@ class Stage: self.functions.append(fun) self.functions_by_id[fun.id] = fun + class Function: """A Function object encapsulates a function on a data set. diff --git a/workflows/affy_workflow.py b/workflows/affy_workflow.py index 89a4dc4..1bebb40 100644 --- a/workflows/affy_workflow.py +++ b/workflows/affy_workflow.py @@ -73,6 +73,8 @@ class DatasetSaveFunction(workflow.Function): if not data: logger.log("notice", "No data to save.") return + else: + data = data[0] chooser = gtk.FileChooserDialog(title="Save pickled data...", parent=None, action=gtk.FILE_CHOOSER_ACTION_SAVE, @@ -101,7 +103,7 @@ class CelFileImportFunction(workflow.Function): def __init__(self): workflow.Function.__init__(self, 'cel_import', 'Import Affy') - def run(self, data): + def run(self, (data,)): import rpy chooser = gtk.FileChooserDialog(title="Select cel files...", parent=None, action=gtk.FILE_CHOOSER_ACTION_OPEN, @@ -150,7 +152,7 @@ class PCAFunction(workflow.Function): workflow.Function.__init__(self, 'pca', 'PCA') self._workflow = wf - def run(self, data): + def run(self, (data,)): import rpy dim_2, dim_1 = data.get_dim_names() diff --git a/workflows/go_workflow.py b/workflows/go_workflow.py index 3df9b5b..dcfa0e1 100644 --- a/workflows/go_workflow.py +++ b/workflows/go_workflow.py @@ -81,7 +81,7 @@ class GODistanceFunction(workflow.Function): workflow.Function.__init__(self, 'go_diatance', 'GO Distances') self.output = None - def run(self, data): + def run(self, (data,)): logger.log('debug', 'datatype: %s' % type(data)) if not type(data) == Annotations: return None @@ -108,7 +108,7 @@ class DatasetLog(workflow.Function): def __init__(self): workflow.Function.__init__(self, 'log', 'Log') - def run(self, data): + def run(self, (data,)): logger.log('notice', 'Taking the log of dataset %s' % data.get_name()) d = data.asarray() d = log(d) @@ -151,7 +151,8 @@ class DatasetSaveFunction(workflow.Function): if not data: logger.log("notice", "No data to save.") return - + else: + data = data[0] chooser = gtk.FileChooserDialog(title="Save pickled data...", parent=None, action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, @@ -179,7 +180,7 @@ class CelFileImportFunction(workflow.Function): def __init__(self): workflow.Function.__init__(self, 'cel_import', 'Import Affy') - def run(self, data): + def run(self, (data,)): import rpy chooser = gtk.FileChooserDialog(title="Select cel files...", parent=None, action=gtk.FILE_CHOOSER_ACTION_OPEN, @@ -228,7 +229,7 @@ class PCAFunction(workflow.Function): workflow.Function.__init__(self, 'pca', 'PCA') self._workflow = wf - def run(self, data): + def run(self, (data,)): import rpy dim_2, dim_1 = data.get_dim_names() diff --git a/workflows/pca_workflow.py b/workflows/pca_workflow.py index 11558a6..e5409f0 100644 --- a/workflows/pca_workflow.py +++ b/workflows/pca_workflow.py @@ -49,7 +49,7 @@ class LoadAnnotationsFunction(Function): logger.log('notice', 'Reading file: %s' % dialog.get_filename()) self.load_affy_file(dialog.get_filename()) - def run(self, data): + def run(self, (data,)): btns = ('Open', gtk.RESPONSE_OK, \ 'Cancel', gtk.RESPONSE_CANCEL) dialog = gtk.FileChooserDialog('Open Affy Annotation File', @@ -81,7 +81,7 @@ class PCAFunction(Function): self.output = None self.workflow = workflow - def run(self, data): + def run(self, (data,)): logger.log('debug', 'datatype: %s' % type(data)) if not isinstance(data,dataset.Dataset): return None @@ -226,7 +226,7 @@ class LoadMoothaData(Function): def __init__(self): Function.__init__(self, 'load', 'Load diabetes data') - def run(self,data): + def run(self,(data,)): data_file = open('full_data.pickle','r') data = pickle.load(data_file) data_file.close() @@ -250,7 +250,7 @@ class Log2Function(Function): def __init__(self): Function.__init__(self, 'log', 'Log2') - def run(self,data): + def run(self,(data,)): x = log2(data._array) #pull out identifiers ids = []