Skip to content
main_controller.py 12.7 KiB
Newer Older
"""

:Author: Franziska Koehn
:Created: 2015/01/13

Franziska Koehn's avatar
Franziska Koehn committed
This module contains the controller that provides the communication between views.
import xsa.datatypereader
from xsagtk.message_dialogs import create_error_message
class QueryController(gobject.GObject):
Franziska Koehn's avatar
Franziska Koehn committed
    """Provides communication between different views."""
Franziska Koehn's avatar
Franziska Koehn committed
    root_key = 'root'
    query_key = 'query'
    labels_key = 'labels'


    _host = ""
    _user = ""
    _passw = ""
    _root = ""
    _query = []
    _labels = []

    @property
    def root(self):
Franziska Koehn's avatar
Franziska Koehn committed
        """Root-Type of search"""
        return self._root

    @root.setter
    def root(self, new_root):
        self._root = new_root

    @property
    def labels(self):
Franziska Koehn's avatar
Franziska Koehn committed
        """Fields of search (label of fields)"""
        return self._labels

    @labels.setter
    def labels(self, new_labels):
        self._labels = new_labels

    @property
    def query(self):
Franziska Koehn's avatar
Franziska Koehn committed
        """List including constraints of query."""
        return self._query

    @query.setter
    def query(self, new_query):
        self._query = new_query

    @property
    def host(self):
Franziska Koehn's avatar
Franziska Koehn committed
        """Host-address"""
        return self._host

    @host.setter
    def host(self, new_host):
        self._host = new_host

    @property
    def credentials_tuple(self):
Franziska Koehn's avatar
Franziska Koehn committed
        """Credentials as tuple (user-name, password)"""
        return (self._user, self._passw)

    @credentials_tuple.setter
    def credentials_tuple(self, creds):
        self._user, self._passw = creds

    @property
    def credentials(self):
Franziska Koehn's avatar
Franziska Koehn committed
        """Credentials as http-auth-string (user-name:password)"""
        return "%s:%s" % self.credentials_tuple

    @credentials.setter
    def credentials(self, new_creds):
        self._user, _, self._passw = new_creds.partition(":")


    def __init__(self, main, queryview, menuview, chartview, resultsview, statusbar):
Franziska Koehn's avatar
Franziska Koehn committed
        Connects signals to views and contains definitions for callbacks of toolbar-buttons.

        **Parameters**
            :main: gtk.Window, main-window
Franziska Koehn's avatar
Franziska Koehn committed
            :queryview: a gtk.Container, View for creating queries
            :menuview: a gtk.Container, View for Menu/Toolbar
            :chartview: a gtk.Container, View including all widgets for the chart
            :resultsview: a gtk.Container, View for showing the results of the search
            :statusbar: a gtk.Container, Statusbar
        super(QueryController, self).__init__()
        self.main = main
        self.queryview = queryview
        self.menuview = menuview
        self.chartview = chartview
        self.resultsview = resultsview
        self.statusbar = statusbar

        def callback_get_additional_data(*_):
Franziska Koehn's avatar
Franziska Koehn committed
            self.get_additional_data()
Franziska Koehn's avatar
Franziska Koehn committed
        def callback_export_csv(*_):
            self.export_csv()
Franziska Koehn's avatar
Franziska Koehn committed
        def callback_edit_Server_Settings(*_):
            self.edit_server_settings()
Franziska Koehn's avatar
Franziska Koehn committed
        def callback_toggle_selection(*_):
            self.resultsview.toggle_selection()
Franziska Koehn's avatar
Franziska Koehn committed
        def callback_download(*_):
            self.download_files()
Franziska Koehn's avatar
Franziska Koehn committed
        def callback_save_query(*_):
            self.update_data()
            self.save_query()
Franziska Koehn's avatar
Franziska Koehn committed
        def callback_load_query(*_):
            self.load_query()
Franziska Koehn's avatar
Franziska Koehn committed
        def callback_send_query(*_):
            self.update_data()
            self.send_query()
Franziska Koehn's avatar
Franziska Koehn committed
        self.menuview.connect("spawn-connection-dialog", callback_edit_Server_Settings)
        self.menuview.connect("send-query", callback_send_query)
        self.menuview.connect("toggle-selection", callback_toggle_selection)
        self.menuview.connect("download-selection", callback_download)
        self.menuview.connect("save-query", callback_save_query)
        self.menuview.connect("load-query", callback_load_query)
        self.menuview.connect("get-additional-data",callback_get_additional_data)
        self.menuview.connect("export-csv", callback_export_csv)
Franziska Koehn's avatar
Franziska Koehn committed
    def update_data(self):
        """updates root, query and labels"""
        self.root = self.queryview.get_root_type()
        self.query = self.queryview.get_query()
        self.labels = self.queryview.get_fields()
        #TODO host/username/password

    def get_additional_data(self):
        """queries for additional data for all items in the result-table"""
        rest = xsa.datatypereader.get_comparison_extra_source(self.root)

        new_data_sets = []
        for r in self.results:
            new_data_sets.append(xsa.queries.query_for_additional_data(rest, r, self.host, self.credentials_tuple))

        keys = []
        for data_set in new_data_sets:
            for key in data_set.keys():
                keys.append(key)

        new_result = []
        for data_set in new_data_sets:
            dic = {}
            for key in keys:
Franziska Koehn's avatar
Franziska Koehn committed
                    dic[key] = data_set[key]
                except:
                    dic[key] = "N/A"
            new_result.append(dic)

        from pyxnat.core.jsonutil import JsonTable
        self.results = JsonTable(new_result)

        self.resultsview.show_data(self.results, self.root)
        self.chartview.update_chart_view(self.results, self.root)

    def export_csv(self):
        """Exports Result-Table as CSV to chosen destination."""
        dialog = gtk.FileChooserDialog( "Save as...",
                                        None,
                                        gtk.FILE_CHOOSER_ACTION_SAVE,
                                        (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_CANCEL)

        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            self.results.dump_csv(dialog.get_filename())
        dialog.destroy()

    def edit_server_settings(self):
        """Creates Dialog to edit server-settings and save changes."""
        dialog = gtk.Dialog(    "Server Settings",
                                None, 0,
                                (   gtk.STOCK_OK, gtk.RESPONSE_OK,
                                    "Cancel", gtk.RESPONSE_CANCEL)
                                )
        dialog.set_resizable(False)
        dialog.set_size_request(330, 180)
        hbox = gtk.HBox(False, 8)
        hbox.set_border_width(8)
        dialog.vbox.pack_start(hbox, True, True, 0)

        stock = gtk.image_new_from_stock(
                gtk.STOCK_DIALOG_AUTHENTICATION,
                gtk.ICON_SIZE_DIALOG)
        hbox.pack_start(stock, False, False, 0)

        table = gtk.Table(2, 3)
        table.set_row_spacings(4)
        table.set_col_spacings(4)
        hbox.pack_start(table, True, True, 0)

        label_user =  gtk.Label()
        label_user.set_text("User:")
        table.attach(label_user, 0, 1, 0, 1)

        entry_user = gtk.Entry()
        entry_user.set_text(self.credentials_tuple[0])
        table.attach(entry_user, 1, 2, 0, 1)

        label_passw =  gtk.Label()
        label_passw.set_text("Password:")
        table.attach(label_passw, 0, 1, 1, 2)

        entry_passw = gtk.Entry()
        entry_passw.set_visibility(False)
        entry_passw.set_text(self.credentials_tuple[1])
        table.attach(entry_passw, 1, 2, 1, 2)

        label_host =  gtk.Label()
        label_host.set_text("Host:")
        table.attach(label_host, 0, 1, 2, 3)

        entry_host = gtk.Entry()
        entry_host.set_text(self.host)
        table.attach(entry_host, 1, 2, 2, 3)

        dialog.show_all()
        response = dialog.run()

        if response == gtk.RESPONSE_OK:
            self.credentials_tuple = (entry_user.get_text(),entry_passw.get_text())
            self.host = entry_host.get_text()
            import xsa.queries
            try:
                xsa.queries.get_xnat_server_connection(force=True, host=self.host, user=self.credentials_tuple[0], passw=self.credentials_tuple[1])
            except Exception as e:
                create_error_message(e)
Franziska Koehn's avatar
Franziska Koehn committed
        dialog.destroy()


    def download_files(self):
        """Downloads files from selected items of Result-Table"""
        if self.resultsview.get_selected_items() == []:
            return

        dialog = gtk.FileChooserDialog( "Open..",
                                        None,
                                        gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
                                        (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)

        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            rest = xsa.datatypereader.get_rest(self.root)
            enabled = (d for d in self.resultsview.get_store() if d[0])
            for d in enabled:
                def stop_spinner(_row):
                    _row[2] = False # Hide spinner
                    _row[0] = False # Checkbox to false
                d[3] = 0
                d[2] = True # Show Spinner
                xsa.queries.download_async( d[1],
                                        self.host,
                                        self.credentials_tuple,
                                        rest,
                                        dialog.get_filename(),
                                        cb=stop_spinner,
                                        cb_args=(d,)
                                        )
        dialog.destroy()

    def save_query(self):
        """Saves defined query as JSON-file"""
        import json

        data = {}
        data.update({self.root_key: self.root})
        data.update({self.query_key: self.query})
        data.update({self.labels_key: self.labels})

        dialog = gtk.FileChooserDialog( "Save as..",
                                        None,
                                        gtk.FILE_CHOOSER_ACTION_SAVE,
                                        (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)
        response = dialog.run()

        if response == gtk.RESPONSE_OK:
            with open(dialog.get_filename(),'w') as file:
                file_data = json.dumps(data)
                file.write(file_data)

        dialog.destroy()

    def load_query(self):
        """Loads a Query from a JSON-File"""
        import json

        dialog = gtk.FileChooserDialog( "Load..",
                                        None,
                                        gtk.FILE_CHOOSER_ACTION_OPEN,
                                        (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)
        response = dialog.run()

        if response == gtk.RESPONSE_OK:
            with open(dialog.get_filename(), 'r') as file:
                f= json.load(file)
                self.queryview.set_data(root_field = f[self.root_key],
                                        query = f[self.query_key],
                                        field_labels = f[self.labels_key]
                                        )
        dialog.destroy()

    def send_query(self):
        """Sends defined query to server, using xsa.queries"""
        import xsa.errors

        user, passw = self.credentials_tuple
        fields = xsa.datatypereader.get_fields_from_labels(self.labels,self.root)
Franziska Koehn's avatar
Franziska Koehn committed
        if passw =='' or user=='' or self.host=='':
            create_error_message("Please set your password, user-name and host-address (use button 'Server Settings').")
            return
        if self.query==[]:
            create_error_message("Please define a query.")
            return

        try:
            self.results = xsa.queries.search_for( self.host, self.root, self.query, fields, user, passw)
        except Exception as e:
            create_error_message(e)
            self.results = []

        self.resultsview.show_data(self.results, self.root)
        self.statusbar.push(0, "%s Results"%len(self.results))
        self.chartview.update_chart_view(self.results, self.root)

        if self.results == []:
            self.menuview.disable_download_button(False, "No Results for downloading")
            self.menuview.disable_export_button(False, "No Results for exporting")
            self.menuview.disable_adddata_button(False, "No Results for getting additional data")
            return
        else:
            try:
                xsa.datatypereader.get_rest(self.root)
                self.menuview.disable_download_button(True, "Download selected items from result-table")
            except xsa.errors.NoRestApiError as e:
                self.menuview.disable_download_button(False, str(e))
Franziska Koehn's avatar
Franziska Koehn committed
            self.menuview.disable_adddata_button(True, "Get additional data")
            self.menuview.disable_export_button(True, "Export Result-Table as csv-file")