Skip to content
xnat_search_gui.py 15.3 KiB
Newer Older
Franziska Koehn's avatar
Franziska Koehn committed
import gtk

class XnatSearchApp(gtk.Window):

    def __init__(self):
        super(XnatSearchApp, self).__init__()

        self.set_size_request(800, 500)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)
        self.set_title("Xnat Search")

        def on_button_send_press_event(button, *_):
            import xnat_search
            host = self.entry_host.get_text()
            query = self.treeView_search.get_query()
            passw = self.entry_passw.get_text()
            user = self.entry_user.get_text()
            results = xnat_search.search_for_mrScanData(host, query, user, passw)

            #TODO cacht errors

            self.treeViewResults.show_data(results)

        vbox_root = gtk.VBox(False, 1)

        hpaned = gtk.HPaned()
        hpaned.set_position(400)
        vbox_root.pack_start(hpaned, True, True, 5)

        vbox_search = gtk.VBox(homogeneous=False, spacing=1)

        hpaned.add1(vbox_search)

        # query-tree
        sw_search = gtk.ScrolledWindow()
        sw_search.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw_search.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        vbox_search.pack_start(sw_search, True, True, 0)

        self.treeView_search = TreeViewSearchQuery()
        sw_search.add(self.treeView_search)

        # login fields
        hBox_cedentials = gtk.HBox(False,5)
        vbox_search.pack_start(hBox_cedentials, expand=False, fill=False)

        label_user =  gtk.Label()
        label_user.set_text("User:")
        hBox_cedentials.pack_start(label_user, expand=False, fill=False)
        self.entry_user = gtk.Entry()
        hBox_cedentials.pack_start(self.entry_user, expand=True, fill=True)

        label_passw =  gtk.Label()
        label_passw.set_text("Password:")
        hBox_cedentials.pack_start(label_passw, expand=False, fill=False)
        self.entry_passw = gtk.Entry()
        self.entry_passw.set_visibility(False)
        hBox_cedentials.pack_start(self.entry_passw, expand=True, fill=True)

        # host-text-field and send-query-button
        hBox_send = gtk.HBox(False,5)
        vbox_search.pack_start(hBox_send, expand=False, fill=False)

        label_host =  gtk.Label()
        label_host.set_text("Host:")
        hBox_send.pack_start(label_host, expand=False, fill=False)

        self.entry_host = gtk.Entry()
        hBox_send.pack_start(self.entry_host, expand=True, fill=True)

        button_send = gtk.Button(label="Send Query")
        button_send.connect("clicked", on_button_send_press_event)
        button_send.show()
        hBox_send.pack_end(button_send, expand=False, fill=False)

        # right site

        vpaned = gtk.VPaned()
        vpaned.set_position(300)
        hpaned.add2(vpaned)

Franziska Koehn's avatar
Franziska Koehn committed
        vBox_results = gtk.VBox(False,1)
        vpaned.add1(vBox_results)

Franziska Koehn's avatar
Franziska Koehn committed
        sw_results = gtk.ScrolledWindow()
        sw_results.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw_results.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
Franziska Koehn's avatar
Franziska Koehn committed
        vBox_results.pack_start(sw_results,expand=True, fill=True)
Franziska Koehn's avatar
Franziska Koehn committed

        self.treeViewResults = TreeViewResults()
        sw_results.add(self.treeViewResults)

Franziska Koehn's avatar
Franziska Koehn committed
        button_download = gtk.Button(label="Download")
        #button_download.connect("clicked", on_button_send_press_event)
        button_download.show()
        vBox_results.pack_end(button_download,expand=False, fill=False)
Franziska Koehn's avatar
Franziska Koehn committed

        # histogramm values and its buttons

Franziska Koehn's avatar
Franziska Koehn committed
        min_width = 220
        def keep_min_width_cb(paned, *_):
            if paned.get_position() < min_width and paned.get_allocation().width>min_width:
                paned.set_position(min_width)

        hpaned_histo = gtk.HPaned()
        hpaned_histo.connect("notify::position", keep_min_width_cb)
        hpaned_histo.set_position(min_width)
        vpaned.add2(hpaned_histo)

        table_histo = gtk.Table(rows=2, columns=2)
        #vBox_histo = gtk.VBox(False,5)
        #hpaned_histo.add1(vBox_histo)
        hpaned_histo.add1(table_histo)

Franziska Koehn's avatar
Franziska Koehn committed
        sw_hist_values = gtk.ScrolledWindow()
        sw_hist_values.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw_hist_values.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
Franziska Koehn's avatar
Franziska Koehn committed
        #vBox_histo.pack_start(sw_hist_values, expand=True, fill=True)
        table_histo.attach(sw_hist_values, 1,3, 1,2)
Franziska Koehn's avatar
Franziska Koehn committed

        self.treeViewHistogrammValues = TreeViewHistogrammValues()
        sw_hist_values.add(self.treeViewHistogrammValues)

        hbox_histo_buttons = gtk.HBox(False,5)
Franziska Koehn's avatar
Franziska Koehn committed
        #vBox_histo.pack_end(hbox_histo_buttons, expand=False, fill=True)
Franziska Koehn's avatar
Franziska Koehn committed

        button_histo_add = gtk.Button(label="Add Value")
        #button_histo_add.connect("clicked", on_button_send_press_event)
        button_histo_add.show()
        hbox_histo_buttons.pack_end(button_histo_add, expand=False, fill=False)

        button_histo_show = gtk.Button(label="Show Histogramm")
        #button_histo_show.connect("clicked", on_button_send_press_event)
        button_histo_show.show()
        hbox_histo_buttons.pack_end(button_histo_show, expand=False, fill=False)
Franziska Koehn's avatar
Franziska Koehn committed
        table_histo.attach(hbox_histo_buttons, 1,3, 2,3, yoptions=gtk.SHRINK)
Franziska Koehn's avatar
Franziska Koehn committed

        # histogramm

Franziska Koehn's avatar
Franziska Koehn committed
        hBox_histogramm = gtk.HBox(False,5)
        hpaned_histo.add2(hBox_histogramm)

Franziska Koehn's avatar
Franziska Koehn committed
        # statusbar

        self.statusbar = gtk.Statusbar()
        vbox_root.pack_start(self.statusbar, False, False, 0)

        self.add(vbox_root)
        self.show_all()

Franziska Koehn's avatar
Franziska Koehn committed

Franziska Koehn's avatar
Franziska Koehn committed
class TreeViewHistogrammValues(gtk.TreeView):

    def __init__(self):
        super(TreeViewHistogrammValues, self).__init__()
        self.create_model()
        self.create_button()

    def create_button(self):

        def cell_edited_callback(cellrenderertext, path_string, new_text, *_):
            it = self.store.get_iter_from_string(path_string)
            self.store.set(it, 0, new_text)

        rendererText = gtk.CellRendererText()
        rendererText.set_property('editable', True)
        rendererText.connect('edited', cell_edited_callback, 2)

        column = gtk.TreeViewColumn("Scan-Type Substring", rendererText, text=0)
        column.set_sort_column_id(0)
        self.append_column(column)

    def create_model(self):
        self.store = gtk.ListStore(str)
        self.store.append(["t1"])
        self.set_model(self.store)

class TreeViewResults(gtk.TreeView):

    def __init__(self):
        super(TreeViewResults, self).__init__()
        self.create_columns()
        self.store = gtk.ListStore(str, str, str, str, str)
        self.set_model(self.store)

    def create_columns(self):

        column = gtk.TreeViewColumn("Project-ID", gtk.CellRendererText(), text=0)
        column.set_sort_column_id(0)
        column.set_resizable(True)
        self.append_column(column)

        column = gtk.TreeViewColumn("Subject-ID", gtk.CellRendererText(), text=1)
        column.set_sort_column_id(1)
        column.set_resizable(True)
        self.append_column(column)

        column = gtk.TreeViewColumn("Session-ID", gtk.CellRendererText(), text=2)
        column.set_sort_column_id(2)
        column.set_resizable(True)
        self.append_column(column)

        column = gtk.TreeViewColumn("Scan-ID", gtk.CellRendererText(), text=3)
        column.set_sort_column_id(3)
        column.set_resizable(True)
        self.append_column(column)

        column = gtk.TreeViewColumn("Scan-Type", gtk.CellRendererText(), text=4)
        column.set_sort_column_id(4)
        column.set_resizable(True)
        self.append_column(column)

    def show_data(self, data):
        self.store.clear()
        for d in data:
            self.store.append( [d['xnat_mrsessiondata_project'],
                                d['xnat_mrsessiondata_subject_id'],
                                d['xnat_mrsessiondata_session_id'],
                                d['id'],
                                d['type']
                                ])

class TreeViewSearchQuery(gtk.TreeView):

    inital_value = "..."
    tooltip = 'Delete by using right click'
    methods = [] #["AND", "OR"]
    types = [] #["TYPE", "TE", "TI"]
    operators = [] #["LIKE", ">", "<", "<=", ">=", "="]

    def __init__(self):
        super(TreeViewSearchQuery, self).__init__()

        self.create_type_list()
        self.create_method_list()
        self.create_operator_list()

        self.set_rules_hint(True)
        self.create_columns()
        self.set_headers_visible(True)
        self.create_model()
        self.set_model(self.store)

        def on_treeview_button_press_event(treeview, event):
            if event.button == 3:
                x = int(event.x)
                y = int(event.y)
                path_info = treeview.get_path_at_pos(x, y)
                if path_info is not None:
                    path, col, cellx, celly = path_info
                    iter = self.store.get_iter(path)
                    if not path == (0,):
                        md = gtk.MessageDialog(type=gtk.MESSAGE_WARNING,
                                               buttons=gtk.BUTTONS_YES_NO,
                                               message_format="Remove the element and its children?"
                                               )
                        response = md.run()
                        md.destroy()
                        if response == gtk.RESPONSE_YES:
                            self.store.remove(iter)

        self.connect('button_press_event', on_treeview_button_press_event)

        self.set_tooltip_column(4)

    def create_columns(self):

        def root_changed_callback(combo, path_string, new_iter, col, del_col, *_):

            it = self.store.get_iter_from_string(path_string)
            new_value = combo.get_property("model")[new_iter][0]
            old_value = self.store.get_value(it, col)

            def append_inital_child(parent):
                last_child = self.store.iter_n_children(parent) -1
                child = self.store.iter_nth_child(parent, last_child)
                if not child is None:
                    child_value = self.store.get_value(child, 0)
                    if not child_value == self.inital_value:
                        self.store.append(parent,  (self.inital_value, '', '', False, self.tooltip))
                else:
                    self.store.append(parent,  (self.inital_value, '', '', False, self.tooltip))

            def set_new_value_and_append_child(has_operator_and_value):
                self.store.set(it, col, str(new_value))
                self.store.set(it, 3, has_operator_and_value)
                if has_operator_and_value:
                    parent = self.store.iter_parent(it)
                    if not parent is None:
                        append_inital_child(parent)
                else:
                    append_inital_child(it)

            if new_value in self.types:
                if (not old_value == self.inital_value) and (not old_value in self.types):
                    md = gtk.MessageDialog(type=gtk.MESSAGE_WARNING,
                                           buttons=gtk.BUTTONS_YES_NO,
                                           message_format="The children will be destroyed!Continue?"
                                           )
                    response = md.run()
                    md.destroy()
                    if response == gtk.RESPONSE_YES:
                        set_new_value_and_append_child(True)
                        while not self.store.iter_children(it) is None:
                            child = self.store.iter_children(it)
                            self.store.remove(child)
                else:
                    set_new_value_and_append_child(True)
            else:
                set_new_value_and_append_child(False)
                for c in del_col:
                    self.store.set(it, c, '')

        def cell_changed_callback(combo, path_string, new_iter, col, *_):
            it = self.store.get_iter_from_string(path_string)
            text = combo.get_property("model")[new_iter][0]
            self.store.set(it, col, str(text))

        def cell_edited_callback(cellrenderertext, path_string, new_text, col, *_):
            it = self.store.get_iter_from_string(path_string)
            self.store.set(it, col, new_text)

        rendererCombo = gtk.CellRendererCombo()
        rendererCombo.set_property('editable', True)
        rendererCombo.set_property ("model", self.create_combo_list_type());
        rendererCombo.set_property ("text-column", 0);
        rendererCombo.connect('changed', root_changed_callback, 0, [1,2])

        column = gtk.TreeViewColumn("", rendererCombo, text=0)
        column.set_sort_column_id(0)
        column.set_min_width(100)
        column.set_resizable(True)
        self.append_column(column)

        rendererCombo = gtk.CellRendererCombo()
        rendererCombo.set_property('editable', True)
        rendererCombo.set_property ("model", self.create_combo_list_operator());
        rendererCombo.set_property ("text-column", 0);
        rendererCombo.connect('changed', cell_changed_callback, 1)

        column = gtk.TreeViewColumn("Operator", rendererCombo, text=1, editable=3)
        column.set_sort_column_id(1)
        column.set_min_width(70)
        self.append_column(column)

        rendererText = gtk.CellRendererText()
        rendererText.set_property('editable', True)
        rendererText.connect('edited', cell_edited_callback, 2)

        column = gtk.TreeViewColumn("Value", rendererText, text=2, editable=3)
        column.set_sort_column_id(2)
        column.set_min_width(100)
        column.set_resizable(True)

        self.append_column(column)

    @staticmethod
    def create_combo_list(labels):
        combo_model = gtk.ListStore(str)
        for l in labels:
            combo_model.append((str(l),))
        return combo_model

    def create_combo_list_type(self):
        return self.create_combo_list(self.methods+self.types)

    def create_combo_list_operator(self):
        return self.create_combo_list(self.operators)

    def create_model(self):
        self.store = gtk.TreeStore(str, str, str, bool, str)
        self.store.append(None, (self.inital_value, '', '', False, self.tooltip))

    def create_type_list(self):
        import xnat_search
        for type in xnat_search.get_search_fields():
            self.types.append(type['label'])

    def create_method_list(self):
        import xnat_search
        self.methods = xnat_search.get_query_methods()

    def create_operator_list(self):
        import xnat_search
        self.operators = xnat_search.get_operators()

    def get_query(self):
        import xnat_search

        search_fields = xnat_search.get_search_fields()
        query = []

        def add_next_to_querry(iter):
            value = self.store.get_value(iter, 0)
            if value in self.methods:
                query.append(value)
            elif value in self.types:
                for field in search_fields:
                    if field['label'] == value:
                        value = field['field']
                operator = self.store.get_value(iter, 1)
                field_value = self.store.get_value(iter, 2)
                query.append( (value, operator, field_value) )
            child = self.store.iter_children(iter)
            if not child is None:
                add_next_to_querry(child)
            next_ = self.store.iter_next(iter)
            if not next_ is None:
                add_next_to_querry(next_)

        it = self.store.get_iter_first()
        add_next_to_querry(it)
        return query

XnatSearchApp()
gtk.main()