Ejemplo n.º 1
0
class ResultList(object):
    """Result list with toolbar"""
    def __init__(self, win, builder):
        self.builder = builder
        self.widget = self.builder.get_object('editor_results_data')
        self._setup_widget()
        self.instance = win
        self.query = None

    def _setup_widget(self):
        self.grid = Grid()
        self.builder.get_object("sw_grid").add(self.grid)

    def set_query(self, query):
        self.query = query
        self.grid.reset()
        if self.query.description:
            try:
                self.grid.set_result(self.query.rows, self.query.description,
                                     self.query.coding_hint)
            except Exception, err:
                logging.exception('Failed to display query results')
                dialogs.error(_(u'Failed to display results'), str(err))
Ejemplo n.º 2
0
class ResultList(object):
    """Result list with toolbar"""

    def __init__(self, win, builder):
        self.builder = builder
        self.widget = self.builder.get_object('editor_results_data')
        self._setup_widget()
        self.instance = win
        self.query = None

    def _setup_widget(self):
        self.grid = Grid()
        self.builder.get_object("sw_grid").add(self.grid)

    def set_query(self, query):
        self.query = query
        self.grid.reset()
        if self.query.description:
            try:
                self.grid.set_result(self.query.rows, self.query.description,
                                     self.query.coding_hint)
            except Exception, err:
                logging.exception('Failed to display query results')
                dialogs.error(_(u'Failed to display results'), str(err))
Ejemplo n.º 3
0
class ResultsView(object):

    def __init__(self, win, builder):
        self.instance = win
        self.app = win.app
        self.widget = builder.get_object('editor_results')
        self.builder = builder
        self._setup_widget()
        self._setup_connections()

    def _setup_widget(self):
        self.grid = ResultList(self.instance, self.builder)
        self.messages = self.builder.get_object("editor_results_messages")
        model = gtk.ListStore(str,  # 0 stock id
                              str,  # 1 message
                              str,  # 2 foreground color
                              int,  # 3 font weight
                              bool, # 4 is separator row
                              str,  # 5 font description
                              )
        model.connect("row-inserted", self._msg_model_changed)
        model.connect("row-deleted", self._msg_model_changed)
        self.messages.set_model(model)
        col = gtk.TreeViewColumn()
        renderer = gtk.CellRendererPixbuf()
        col.pack_start(renderer, expand=False)
        col.add_attribute(renderer, 'stock-id', 0)
        renderer = gtk.CellRendererText()
        col.pack_start(renderer, expand=True)
        col.add_attribute(renderer, 'text', 1)
        col.add_attribute(renderer, 'foreground', 2)
        col.add_attribute(renderer, 'weight', 3)
        col.add_attribute(renderer, 'font', 5)
        self.messages.append_column(col)
        self.messages.set_row_separator_func(self._set_row_separator)
        self.explain_results = Grid()
        sw = self.builder.get_object('sw_explain_results')
        sw.add(self.explain_results)
        self.explain_results.show_all()
        self._update_btn_export_state()

    def _update_btn_export_state(self):
        """Update state of export button."""
        btn_export = self.builder.get_object('editor_export_data')
        rows = None
        if self.grid.query:
            rows = self.grid.query.rows
        sensitive = False
        if rows:
            sensitive = True
            exp_plugins = self.app.plugins.get_plugins(PLUGIN_TYPE_EXPORT,
                                                       True)
            if not exp_plugins:
                sensitive = False
        btn_export.set_sensitive(sensitive)

    def _msg_model_changed(self, model, *args):
        tb_clear = self.builder.get_object("tb_messages_clear")
        tb_copy = self.builder.get_object("tb_messages_copy")
        sensitive = model.get_iter_first() is not None
        tb_clear.set_sensitive(sensitive)
        tb_copy.set_sensitive(sensitive)

    def _setup_connections(self):
        self.grid.grid.connect("selection-changed",
                               self.on_grid_selection_changed)
        self.app.plugins.connect('plugin-added',
                                 lambda *a: self._update_btn_export_state())
        self.app.plugins.connect('plugin-removed',
                                 lambda *a: self._update_btn_export_state())
        self.app.plugins.connect('plugin-active',
                                 lambda *a: self._update_btn_export_state())

    def _set_row_separator(self, model, iter):
        return model.get_value(iter, 4)

    def on_copy_data(self, *args):
        gobject.idle_add(self.copy_data)

    def on_export_data(self, *args):
        gobject.idle_add(self.export_data)

    def on_messages_clear(self, *args):
        self.messages.get_model().clear()

    def on_messages_copy(self, *args):
        model = self.messages.get_model()
        iter_ = model.get_iter_first()
        plain = []
        while iter_ is not None:
            if model.get_value(iter_, 4): # Is it a separator?
                plain.append('-'*20)
            else:
                value = model.get_value(iter_, 1)
                if value is not None:
                    plain.append(value)
            iter_ = model.iter_next(iter_)
        clipboard = gtk.clipboard_get()
        clipboard.set_text('\n'.join(plain))

    def on_grid_selection_changed(self, grid, selected_cells):
        self.builder.get_object("editor_copy_data").set_sensitive(bool(selected_cells))

    def assure_visible(self):
        """Make sure that the result pane is visible."""
        pane = self.widget.get_parent()
        if not pane.get_property('visible'):
            pane.show()

    def copy_data(self, clipboard=None):
        """Copy selected values to clipboard.

        Columns are terminated by \t, rows by \n.
        If *clipboard* is ``None``, the default clipboard will be used.
        """
        rows = {}
        for cell in self.grid.grid.get_selected_cells():
            value = self.grid.grid.get_cell_data(cell, repr=True)
            if rows.has_key(cell[0]):
                rows[cell[0]] += "\t%s" % value
            else:
                rows[cell[0]] = "%s" % value
        rownums = rows.keys()
        rownums.sort()
        txt = "\n".join(rows.get(rownum) for rownum in rownums)
        if clipboard is None:
            display = gtk.gdk.display_manager_get().get_default_display()
            clipboard = gtk.Clipboard(display, "CLIPBOARD")
        clipboard.set_text(txt)
        self.instance.statusbar.set_message(_(u"Data copied to clipboard"))

    def export_data(self):
        data = self.grid.grid.get_grid_data()
        description = self.grid.grid.description
        selected = self.grid.grid.get_selected_rows()
        statement = self.grid.query.statement
        gtk.gdk.threads_enter()
        dlg = DataExportDialog(self.instance.app, self.instance,
                               data, selected, statement, description)
        if dlg.run() == gtk.RESPONSE_OK:
            dlg.hide()
            dlg.export_data()
        dlg.destroy()
        gtk.gdk.threads_leave()

    def clipboard_copy(self, clipboard):
        """Copies selected cells to clipboard."""
        # TODO: Cleanup API. There should be one function to do this.
        self.copy_data(clipboard)

    def reset(self):
        # Explain
        self.explain_results.reset()
        # Messages
        # Only gray out messages from previous runs, don't remove them!
        model = self.messages.get_model()
        iter_ = model.get_iter_first()
        while iter_:
            model.set_value(iter_, 2, '#cccccc')
            iter_ = model.iter_next(iter_)
        self.widget.set_current_page(2)

    def set_explain_results(self, query):
        self.explain_results.reset()
        if query.failed:
            dialogs.error(_(u'Failed'), '\n'.join(query.errors),
                          parent=self.instance)
        else:
            self.explain_results.set_result(query.rows, query.description)

    def set_query(self, query):
        self.assure_visible()
        self.grid.set_query(query)
        model = self.messages.get_model()
        for err in query.errors:
            self.add_error(err.strip(), monospaced=True)
        for msg in query.messages:
            self.add_output(msg.strip())
        if query.errors:
            curr_page = 2
        elif query.description:
            curr_page = 0
        else:
            curr_page = 2
        self._update_btn_export_state()
        gobject.idle_add(self.widget.set_current_page, curr_page)

    def add_message(self, msg, type_=None, path=None, monospaced=False):
        """Add a message.

        Args:
          msg: The message to add.
          type_: Message type ('info', 'output',
                 'error', 'warning', 'query', None).
        """
        self.assure_visible()
        assert type_ in (None, 'info', 'output', 'error', 'warning', 'query')
        stock_id = None
        foreground = None
        if monospaced:
            font = 'Monospace 10'
        else:
            font = None
        weight = pango.WEIGHT_NORMAL
        if type_ == 'info':
            stock_id = 'gtk-info'
            foreground = '#336699'
        elif type_ == 'error':
            stock_id = 'gtk-dialog-error'
            foreground = '#a40000'
            weight = pango.WEIGHT_BOLD
        elif type_ == 'warning':
            stock_id = 'gtk-dialog-warning'
            foreground = '#00a400'
        elif type_ == 'query':
            stock_id ='gtk-execute'
            weight = pango.WEIGHT_BOLD
        elif type_ == 'output':
            stock_id = 'gtk-go-back'
            font = 'Monospace'
        model = self.messages.get_model()
        if model is None:  # we are in shutdown phase
            return
        msg = msg.strip()
        if path is None:
            itr = model.append([stock_id, msg, foreground, weight,
                                False, font])
        else:
            try:
                iter_ = model.get_iter(path)
            except ValueError:
                return
            model.set_value(iter_, 0, stock_id)
            model.set_value(iter_, 1, msg)
            model.set_value(iter_, 2, foreground)
            model.set_value(iter_, 3, weight)
            model.set_value(iter_, 5, font)
            itr = iter_
        # Somehow this works smarter than treeview.scroll_to_cell(path).
        # See: http://www.mail-archive.com/[email protected]/msg17059.html
        self.messages.scroll_to_cell(str(len(model)-1))
        self.widget.set_current_page(2)
        return model.get_path(itr)

    def add_error(self, msg, monospaced=False):
        return self.add_message(msg, 'error', monospaced=monospaced)

    def add_info(self, msg):
        return self.add_message(msg, 'info')

    def add_warning(self, msg):
        return self.add_message(msg, 'warning')

    def add_output(self, msg):
        return self.add_message(msg, 'output')

    def add_separator(self):
        model = self.messages.get_model()
        if not model.get_iter_first():
            return
        model.append([None, None, None, pango.WEIGHT_NORMAL, True, None])
Ejemplo n.º 4
0
class ResultsView(object):
    def __init__(self, win, builder):
        self.instance = win
        self.app = win.app
        self.widget = builder.get_object('editor_results')
        self.builder = builder
        self._setup_widget()
        self._setup_connections()

    def _setup_widget(self):
        self.grid = ResultList(self.instance, self.builder)
        self.messages = self.builder.get_object("editor_results_messages")
        model = gtk.ListStore(
            str,  # 0 stock id
            str,  # 1 message
            str,  # 2 foreground color
            int,  # 3 font weight
            bool,  # 4 is separator row
            str,  # 5 font description
        )
        model.connect("row-inserted", self._msg_model_changed)
        model.connect("row-deleted", self._msg_model_changed)
        self.messages.set_model(model)
        col = gtk.TreeViewColumn()
        renderer = gtk.CellRendererPixbuf()
        col.pack_start(renderer, expand=False)
        col.add_attribute(renderer, 'stock-id', 0)
        renderer = gtk.CellRendererText()
        col.pack_start(renderer, expand=True)
        col.add_attribute(renderer, 'text', 1)
        col.add_attribute(renderer, 'foreground', 2)
        col.add_attribute(renderer, 'weight', 3)
        col.add_attribute(renderer, 'font', 5)
        self.messages.append_column(col)
        self.messages.set_row_separator_func(self._set_row_separator)
        self.explain_results = Grid()
        sw = self.builder.get_object('sw_explain_results')
        sw.add(self.explain_results)
        self.explain_results.show_all()
        self._update_btn_export_state()

    def _update_btn_export_state(self):
        """Update state of export button."""
        btn_export = self.builder.get_object('editor_export_data')
        rows = None
        if self.grid.query:
            rows = self.grid.query.rows
        sensitive = False
        if rows:
            sensitive = True
            exp_plugins = self.app.plugins.get_plugins(PLUGIN_TYPE_EXPORT,
                                                       True)
            if not exp_plugins:
                sensitive = False
        btn_export.set_sensitive(sensitive)

    def _msg_model_changed(self, model, *args):
        tb_clear = self.builder.get_object("tb_messages_clear")
        tb_copy = self.builder.get_object("tb_messages_copy")
        sensitive = model.get_iter_first() is not None
        tb_clear.set_sensitive(sensitive)
        tb_copy.set_sensitive(sensitive)

    def _setup_connections(self):
        self.grid.grid.connect("selection-changed",
                               self.on_grid_selection_changed)
        self.app.plugins.connect('plugin-added',
                                 lambda *a: self._update_btn_export_state())
        self.app.plugins.connect('plugin-removed',
                                 lambda *a: self._update_btn_export_state())
        self.app.plugins.connect('plugin-active',
                                 lambda *a: self._update_btn_export_state())

    def _set_row_separator(self, model, iter):
        return model.get_value(iter, 4)

    def on_copy_data(self, *args):
        gobject.idle_add(self.copy_data)

    def on_export_data(self, *args):
        gobject.idle_add(self.export_data)

    def on_messages_clear(self, *args):
        self.messages.get_model().clear()

    def on_messages_copy(self, *args):
        model = self.messages.get_model()
        iter_ = model.get_iter_first()
        plain = []
        while iter_ is not None:
            if model.get_value(iter_, 4):  # Is it a separator?
                plain.append('-' * 20)
            else:
                value = model.get_value(iter_, 1)
                if value is not None:
                    plain.append(value)
            iter_ = model.iter_next(iter_)
        clipboard = gtk.clipboard_get()
        clipboard.set_text('\n'.join(plain))

    def on_grid_selection_changed(self, grid, selected_cells):
        self.builder.get_object("editor_copy_data").set_sensitive(
            bool(selected_cells))

    def assure_visible(self):
        """Make sure that the result pane is visible."""
        pane = self.widget.get_parent()
        if not pane.get_property('visible'):
            pane.show()

    def copy_data(self, clipboard=None):
        """Copy selected values to clipboard.

        Columns are terminated by \t, rows by \n.
        If *clipboard* is ``None``, the default clipboard will be used.
        """
        rows = {}
        for cell in self.grid.grid.get_selected_cells():
            value = self.grid.grid.get_cell_data(cell, repr=True)
            if rows.has_key(cell[0]):
                rows[cell[0]] += "\t%s" % value
            else:
                rows[cell[0]] = "%s" % value
        rownums = rows.keys()
        rownums.sort()
        txt = "\n".join(rows.get(rownum) for rownum in rownums)
        if clipboard is None:
            display = gtk.gdk.display_manager_get().get_default_display()
            clipboard = gtk.Clipboard(display, "CLIPBOARD")
        clipboard.set_text(txt)
        self.instance.statusbar.set_message(_(u"Data copied to clipboard"))

    def export_data(self):
        data = self.grid.grid.get_grid_data()
        description = self.grid.grid.description
        selected = self.grid.grid.get_selected_rows()
        statement = self.grid.query.statement
        gtk.gdk.threads_enter()
        dlg = DataExportDialog(self.instance.app, self.instance, data,
                               selected, statement, description)
        if dlg.run() == gtk.RESPONSE_OK:
            dlg.hide()
            dlg.export_data()
        dlg.destroy()
        gtk.gdk.threads_leave()

    def clipboard_copy(self, clipboard):
        """Copies selected cells to clipboard."""
        # TODO: Cleanup API. There should be one function to do this.
        self.copy_data(clipboard)

    def reset(self):
        # Explain
        self.explain_results.reset()
        # Messages
        # Only gray out messages from previous runs, don't remove them!
        model = self.messages.get_model()
        iter_ = model.get_iter_first()
        while iter_:
            model.set_value(iter_, 2, '#cccccc')
            iter_ = model.iter_next(iter_)
        self.widget.set_current_page(2)

    def set_explain_results(self, query):
        self.explain_results.reset()
        if query.failed:
            dialogs.error(_(u'Failed'),
                          '\n'.join(query.errors),
                          parent=self.instance)
        else:
            self.explain_results.set_result(query.rows, query.description)

    def set_query(self, query):
        self.assure_visible()
        self.grid.set_query(query)
        model = self.messages.get_model()
        for err in query.errors:
            self.add_error(err.strip(), monospaced=True)
        for msg in query.messages:
            self.add_output(msg.strip())
        if query.errors:
            curr_page = 2
        elif query.description:
            curr_page = 0
        else:
            curr_page = 2
        self._update_btn_export_state()
        gobject.idle_add(self.widget.set_current_page, curr_page)

    def add_message(self, msg, type_=None, path=None, monospaced=False):
        """Add a message.

        Args:
          msg: The message to add.
          type_: Message type ('info', 'output',
                 'error', 'warning', 'query', None).
        """
        self.assure_visible()
        assert type_ in (None, 'info', 'output', 'error', 'warning', 'query')
        stock_id = None
        foreground = None
        if monospaced:
            font = 'Monospace 10'
        else:
            font = None
        weight = pango.WEIGHT_NORMAL
        if type_ == 'info':
            stock_id = 'gtk-info'
            foreground = '#336699'
        elif type_ == 'error':
            stock_id = 'gtk-dialog-error'
            foreground = '#a40000'
            weight = pango.WEIGHT_BOLD
        elif type_ == 'warning':
            stock_id = 'gtk-dialog-warning'
            foreground = '#00a400'
        elif type_ == 'query':
            stock_id = 'gtk-execute'
            weight = pango.WEIGHT_BOLD
        elif type_ == 'output':
            stock_id = 'gtk-go-back'
            font = 'Monospace'
        model = self.messages.get_model()
        if model is None:  # we are in shutdown phase
            return
        msg = msg.strip()
        if path is None:
            itr = model.append(
                [stock_id, msg, foreground, weight, False, font])
        else:
            try:
                iter_ = model.get_iter(path)
            except ValueError:
                return
            model.set_value(iter_, 0, stock_id)
            model.set_value(iter_, 1, msg)
            model.set_value(iter_, 2, foreground)
            model.set_value(iter_, 3, weight)
            model.set_value(iter_, 5, font)
            itr = iter_
        # Somehow this works smarter than treeview.scroll_to_cell(path).
        # See: http://www.mail-archive.com/[email protected]/msg17059.html
        self.messages.scroll_to_cell(str(len(model) - 1))
        self.widget.set_current_page(2)
        return model.get_path(itr)

    def add_error(self, msg, monospaced=False):
        return self.add_message(msg, 'error', monospaced=monospaced)

    def add_info(self, msg):
        return self.add_message(msg, 'info')

    def add_warning(self, msg):
        return self.add_message(msg, 'warning')

    def add_output(self, msg):
        return self.add_message(msg, 'output')

    def add_separator(self):
        model = self.messages.get_model()
        if not model.get_iter_first():
            return
        model.append([None, None, None, pango.WEIGHT_NORMAL, True, None])