Пример #1
0
    def __init__(self, emma):
        """
        @param emma: Emma
        """
        super(QueryTab, self).__init__()
        self.xml = gtk.glade.XML(
            os.path.join(emma.glade_path, 'querytab.glade'), "first_query")
        self.xml.signal_autoconnect(self)

        self.tab_label.set_text('Query')
        self.tab_label_icon.set_from_file(
            os.path.join(icons_path, 'page_code.png'))

        self.emma = emma

        self.save_result = self.xml.get_widget('save_result')
        self.save_result_sql = self.xml.get_widget('save_result_sql')
        self.local_search = self.xml.get_widget('local_search_button')
        self.remove_order = self.xml.get_widget('remove_order')

        self.label = self.xml.get_widget('query_label')

        self.add_record = self.xml.get_widget('add_record_tool')
        self.delete_record = self.xml.get_widget('delete_record_tool')

        self.query_bottom_label = self.xml.get_widget('query_bottom_label')
        self.query_db_label = self.xml.get_widget('query_db_label')

        self.textview = self.xml.get_widget('query_text')

        self.query_text_sw = self.xml.get_widget('query_text_sw')
        self.apply_record = self.xml.get_widget('apply_record_tool')
        self.ui = self.xml.get_widget('first_query')
        self.toolbar = self.xml.get_widget('inner_query_toolbar')
        self.toolbar.set_style(gtk.TOOLBAR_ICONS)

        self.scrolledwindow6 = self.xml.get_widget('scrolledwindow6')
        self.treeview = QueryTabTreeView(emma)
        self.scrolledwindow6.add(self.treeview)
        self.treeview.show()

        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        self.treeview.connect('cursor_changed',
                              self.on_query_view_cursor_changed)
        # todo: move to keymap
        self.treeview.connect('key_press_event',
                              self.on_query_view_key_press_event)
        self.treeview.connect('button_press_event',
                              self.on_query_view_button_press_event)

        self.execution_timer_running = False
        self.execution_timer_interval = 0
        self.editable = False

        self.sort_timer_running = False
        self.sort_timer_execute = 0

        self.query_encoding_menu = None

        self.filled_fields = []

        # replace textview with gtksourcevice
        try:
            org_tv = self.textview
            manager = gtksourceview2.language_manager_get_default()
            language = manager.get_language("sql")

            sb = gtksourceview2.Buffer()
            sb.set_highlight_syntax(True)
            sb.set_language(language)
            sv = self.textview = gtksourceview2.View(sb)

            self.query_text_sw.remove(org_tv)
            self.query_text_sw.add(sv)
            sv.show()

            sv.set_show_line_numbers(True)
            sv.set_show_line_marks(True)
            sv.set_tab_width(4)
            sv.set_auto_indent(True)
            sv.set_insert_spaces_instead_of_tabs(False)
            sv.set_show_right_margin(True)
            sv.set_smart_home_end(True)
            sv.set_right_margin_position(80)

            # sv config
            # for pt, pn, pd in (
            #     (bool, "show_line_numbers", True),
            #     #(bool, "show_line_markers", False),
            #     #(int, "tabs_width", 4),
            #     (bool, "auto_indent", True),
            #     (bool, "insert_spaces_instead_of_tabs", False),
            #     #(bool, "show_margin", True),
            #     #(int, "margin", 80),
            #     (bool, "smart_home_end", True)
            # ):
            #
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sv, "set_%s" % pn)
            #     method(v)
            # sb config
            # for pt, pn, pd in (
            #     (bool, "check_brackets", True),
            #     (bool, "highlight", True),
            #     (int, "max_undo_levels", 15)
            # ):
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sb, "set_%s" % pn)
            #     method(v)
        except:
            dialogs.alert(traceback.format_exc())

        self.current_host = None
        self.current_db = None
        self.model = None
        self.last_source = None
        self.result_info = None
        self.append_iter = None
        self.last_path = None
        self.encoding = None
        if hasattr(self, "query"):
            self.textview.get_buffer().set_text(self.query)
        self.last_auto_name = None

        #
        #   INIT Query tab actions
        #

        self.remember_order_action = QueryTabRememberOrder(self, emma)
        self.remove_order_action = QueryTabRemoveOrder(self, emma)
        self.set_result_font_action = QueryTabSetResultFont(self, emma)
        self.local_search_action = QueryTabLocalSearch(self, emma)
        self.save_result_sql_action = QueryTabSaveResultSql(self, emma)
        self.save_result_csv_action = QueryTabSaveResultCsv(self, emma)
        self.manage_row_action = QueryTabManageRow(self, emma)

        #
        #
        #

        self.emma.key_map.connect('key-release', self.key_release)
        self.init_from_config()
Пример #2
0
    def __init__(self, emma):
        """
        @param emma: Emma
        """
        super(QueryTab, self).__init__()
        self.xml = gtk.glade.XML(os.path.join(emma.glade_path, "querytab.glade"), "first_query")
        self.xml.signal_autoconnect(self)

        self.tab_label.set_text("Query")
        self.tab_label_icon.set_from_file(os.path.join(icons_path, "page_code.png"))

        self.emma = emma

        self.save_result = self.xml.get_widget("save_result")
        self.save_result_sql = self.xml.get_widget("save_result_sql")
        self.local_search = self.xml.get_widget("local_search_button")
        self.remove_order = self.xml.get_widget("remove_order")

        self.label = self.xml.get_widget("query_label")

        self.add_record = self.xml.get_widget("add_record_tool")
        self.delete_record = self.xml.get_widget("delete_record_tool")

        self.query_bottom_label = self.xml.get_widget("query_bottom_label")
        self.query_db_label = self.xml.get_widget("query_db_label")

        self.textview = self.xml.get_widget("query_text")

        self.query_text_sw = self.xml.get_widget("query_text_sw")
        self.apply_record = self.xml.get_widget("apply_record_tool")
        self.ui = self.xml.get_widget("first_query")
        self.toolbar = self.xml.get_widget("inner_query_toolbar")
        self.toolbar.set_style(gtk.TOOLBAR_ICONS)

        self.scrolledwindow6 = self.xml.get_widget("scrolledwindow6")
        self.treeview = QueryTabTreeView(emma)
        self.scrolledwindow6.add(self.treeview)
        self.treeview.show()

        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        self.treeview.connect("cursor_changed", self.on_query_view_cursor_changed)
        # todo: move to keymap
        self.treeview.connect("key_press_event", self.on_query_view_key_press_event)
        self.treeview.connect("button_press_event", self.on_query_view_button_press_event)

        self.execution_timer_running = False
        self.execution_timer_interval = 0
        self.editable = False

        self.sort_timer_running = False
        self.sort_timer_execute = 0

        self.query_encoding_menu = None

        self.filled_fields = []

        # replace textview with gtksourcevice
        try:
            org_tv = self.textview
            manager = gtksourceview2.language_manager_get_default()
            language = manager.get_language("sql")

            sb = gtksourceview2.Buffer()
            sb.set_highlight_syntax(True)
            sb.set_language(language)
            sv = self.textview = gtksourceview2.View(sb)

            self.query_text_sw.remove(org_tv)
            self.query_text_sw.add(sv)
            sv.show()

            sv.set_show_line_numbers(True)
            sv.set_show_line_marks(True)
            sv.set_tab_width(4)
            sv.set_auto_indent(True)
            sv.set_insert_spaces_instead_of_tabs(False)
            sv.set_show_right_margin(True)
            sv.set_smart_home_end(True)
            sv.set_right_margin_position(80)

            # sv config
            # for pt, pn, pd in (
            #     (bool, "show_line_numbers", True),
            #     #(bool, "show_line_markers", False),
            #     #(int, "tabs_width", 4),
            #     (bool, "auto_indent", True),
            #     (bool, "insert_spaces_instead_of_tabs", False),
            #     #(bool, "show_margin", True),
            #     #(int, "margin", 80),
            #     (bool, "smart_home_end", True)
            # ):
            #
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sv, "set_%s" % pn)
            #     method(v)
            # sb config
            # for pt, pn, pd in (
            #     (bool, "check_brackets", True),
            #     (bool, "highlight", True),
            #     (int, "max_undo_levels", 15)
            # ):
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sb, "set_%s" % pn)
            #     method(v)
        except:
            dialogs.alert(traceback.format_exc())

        self.current_host = None
        self.current_db = None
        self.model = None
        self.last_source = None
        self.result_info = None
        self.append_iter = None
        self.last_path = None
        self.encoding = None
        if hasattr(self, "query"):
            self.textview.get_buffer().set_text(self.query)
        self.last_auto_name = None

        #
        #   INIT Query tab actions
        #

        self.remember_order_action = QueryTabRememberOrder(self, emma)
        self.remove_order_action = QueryTabRemoveOrder(self, emma)
        self.set_result_font_action = QueryTabSetResultFont(self, emma)
        self.local_search_action = QueryTabLocalSearch(self, emma)
        self.save_result_sql_action = QueryTabSaveResultSql(self, emma)
        self.save_result_csv_action = QueryTabSaveResultCsv(self, emma)
        self.manage_row_action = QueryTabManageRow(self, emma)

        #
        #
        #

        self.emma.key_map.connect("key-release", self.key_release)
        self.init_from_config()
Пример #3
0
class QueryTab(widgets.BaseTab):
    def __init__(self, emma):
        """
        @param emma: Emma
        """
        super(QueryTab, self).__init__()
        self.xml = gtk.glade.XML(
            os.path.join(emma.glade_path, 'querytab.glade'), "first_query")
        self.xml.signal_autoconnect(self)

        self.tab_label.set_text('Query')
        self.tab_label_icon.set_from_file(
            os.path.join(icons_path, 'page_code.png'))

        self.emma = emma

        self.save_result = self.xml.get_widget('save_result')
        self.save_result_sql = self.xml.get_widget('save_result_sql')
        self.local_search = self.xml.get_widget('local_search_button')
        self.remove_order = self.xml.get_widget('remove_order')

        self.label = self.xml.get_widget('query_label')

        self.add_record = self.xml.get_widget('add_record_tool')
        self.delete_record = self.xml.get_widget('delete_record_tool')

        self.query_bottom_label = self.xml.get_widget('query_bottom_label')
        self.query_db_label = self.xml.get_widget('query_db_label')

        self.textview = self.xml.get_widget('query_text')

        self.query_text_sw = self.xml.get_widget('query_text_sw')
        self.apply_record = self.xml.get_widget('apply_record_tool')
        self.ui = self.xml.get_widget('first_query')
        self.toolbar = self.xml.get_widget('inner_query_toolbar')
        self.toolbar.set_style(gtk.TOOLBAR_ICONS)

        self.scrolledwindow6 = self.xml.get_widget('scrolledwindow6')
        self.treeview = QueryTabTreeView(emma)
        self.scrolledwindow6.add(self.treeview)
        self.treeview.show()

        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        self.treeview.connect('cursor_changed',
                              self.on_query_view_cursor_changed)
        # todo: move to keymap
        self.treeview.connect('key_press_event',
                              self.on_query_view_key_press_event)
        self.treeview.connect('button_press_event',
                              self.on_query_view_button_press_event)

        self.execution_timer_running = False
        self.execution_timer_interval = 0
        self.editable = False

        self.sort_timer_running = False
        self.sort_timer_execute = 0

        self.query_encoding_menu = None

        self.filled_fields = []

        # replace textview with gtksourcevice
        try:
            org_tv = self.textview
            manager = gtksourceview2.language_manager_get_default()
            language = manager.get_language("sql")

            sb = gtksourceview2.Buffer()
            sb.set_highlight_syntax(True)
            sb.set_language(language)
            sv = self.textview = gtksourceview2.View(sb)

            self.query_text_sw.remove(org_tv)
            self.query_text_sw.add(sv)
            sv.show()

            sv.set_show_line_numbers(True)
            sv.set_show_line_marks(True)
            sv.set_tab_width(4)
            sv.set_auto_indent(True)
            sv.set_insert_spaces_instead_of_tabs(False)
            sv.set_show_right_margin(True)
            sv.set_smart_home_end(True)
            sv.set_right_margin_position(80)

            # sv config
            # for pt, pn, pd in (
            #     (bool, "show_line_numbers", True),
            #     #(bool, "show_line_markers", False),
            #     #(int, "tabs_width", 4),
            #     (bool, "auto_indent", True),
            #     (bool, "insert_spaces_instead_of_tabs", False),
            #     #(bool, "show_margin", True),
            #     #(int, "margin", 80),
            #     (bool, "smart_home_end", True)
            # ):
            #
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sv, "set_%s" % pn)
            #     method(v)
            # sb config
            # for pt, pn, pd in (
            #     (bool, "check_brackets", True),
            #     (bool, "highlight", True),
            #     (int, "max_undo_levels", 15)
            # ):
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sb, "set_%s" % pn)
            #     method(v)
        except:
            dialogs.alert(traceback.format_exc())

        self.current_host = None
        self.current_db = None
        self.model = None
        self.last_source = None
        self.result_info = None
        self.append_iter = None
        self.last_path = None
        self.encoding = None
        if hasattr(self, "query"):
            self.textview.get_buffer().set_text(self.query)
        self.last_auto_name = None

        #
        #   INIT Query tab actions
        #

        self.remember_order_action = QueryTabRememberOrder(self, emma)
        self.remove_order_action = QueryTabRemoveOrder(self, emma)
        self.set_result_font_action = QueryTabSetResultFont(self, emma)
        self.local_search_action = QueryTabLocalSearch(self, emma)
        self.save_result_sql_action = QueryTabSaveResultSql(self, emma)
        self.save_result_csv_action = QueryTabSaveResultCsv(self, emma)
        self.manage_row_action = QueryTabManageRow(self, emma)

        #
        #
        #

        self.emma.key_map.connect('key-release', self.key_release)
        self.init_from_config()

    def init_from_config(self):
        self.set_query_encoding(self.emma.config.get("db_encoding"))
        self.set_query_font(self.emma.config.get("query_text_font"))
        self.set_result_font(self.emma.config.get("query_result_font"))
        if self.emma.config.get_bool("query_text_wrap"):
            self.set_wrap_mode(gtk.WRAP_WORD)
        else:
            self.set_wrap_mode(gtk.WRAP_NONE)
        self.set_current_host(self.emma.current_host)

    def key_release(self, key_map, event):
        pass

    def on_query_view_cursor_changed(self, tv):
        self.emma.blob_view.encoding = self.encoding
        path, column = self.treeview.get_cursor()

        if not path:
            return

        _iter = self.model.get_iter(path)
        if column is not None:
            col = self.treeview.get_columns().index(column)
        else:
            col = 0
        value = self.model.get_value(_iter, col)
        if value is None:
            # todo signal null value
            self.emma.blob_view.buffer.set_text("")
        else:
            self.emma.blob_view.buffer.set_text(value)
        self.emma.blob_view.tv.set_sensitive(True)

        if self.append_iter:
            if path == self.model.get_path(self.append_iter):
                return
            self.manage_row_action.on_apply_record_tool_clicked(None)

    # todo: move to keymap
    def on_query_view_key_press_event(self, tv, event):
        path, column = self.treeview.get_cursor()
        if event.keyval == keysyms.F2:
            self.treeview.set_cursor(path, column, True)
            return True

        if not self.model:
            return False

        _iter = self.model.get_iter(path)
        if event.keyval == keysyms.Down and not self.model.iter_next(_iter):
            if self.append_iter and not self.manage_row_action.on_apply_record_tool_clicked(
                    None):
                return True
            self.manage_row_action.on_add_record_tool_clicked(None)
            return True

    def on_query_view_button_press_event(self, tv, event):
        selection = tv.get_selection()

        print selection.get_selected_rows()

        if event.button != 3 or selection.count_selected_rows() == 0:
            return False

        is_single_row = selection.count_selected_rows() == 1

        menu = QueryTabResultPopup(self, is_single_row)

        menu.popup(None, None, None, 0, 0)  # strange!
        #
        #   If selection is single row - let change row focus
        #
        if is_single_row:
            return False
        else:
            return True

    def on_query_bottom_eventbox_button_press_event(self, ebox, event):
        if not self.query_encoding_menu:
            self.query_encoding_menu = QueryTabPopupEncoding(self)
        self.query_encoding_menu.popup(None, None, None, event.button,
                                       event.time)

    def on_query_db_eventbox_button_press_event(self, ebox, event):
        q = self
        host = q.current_host
        db = q.current_db
        if q.last_path is not None:
            try:
                self.emma.connections_tv.connections_model.get_iter(
                    q.last_path)
                self.emma.connections_tv.set_cursor(q.last_path)
                return
            except:
                # path was not valid
                pass

        i = self.emma.connections_tv.connections_model.get_iter_root()
        while i and self.emma.connections_tv.connections_model.iter_is_valid(
                i):
            if self.emma.connections_tv.connections_model[i][0] == host:
                break
            i = self.emma.connections_tv.connections_model.iter_next(i)
        else:
            print "host not found in connections list!"
            q.current_host = q.current_db = None
            q.update_db_label()
            return

        host_path = self.emma.connections_tv.connections_model.get_path(i)
        self.emma.connections_tv.scroll_to_cell(host_path,
                                                column=None,
                                                use_align=True,
                                                row_align=0.0,
                                                col_align=0.0)
        if db is None:
            self.emma.connections_tv.set_cursor(host_path)
            return
        k = self.emma.connections_tv.connections_model.iter_children(i)
        while k and self.emma.connections_tv.connections_model.iter_is_valid(
                k):
            if self.emma.connections_tv.connections_model[k][0] == db:
                break
            k = self.emma.connections_tv.connections_model.iter_next(k)
        else:
            print "database not found in connections list!"
            q.current_db = None
            q.update_db_label()
            self.emma.connections_tv.set_cursor(host_path)
            return
        path = self.emma.connections_tv.connections_model.get_path(k)
        #self.connections_tv.scroll_to_cell(path, column=None, use_align=True, row_align=0.125, col_align=0.0)
        self.emma.connections_tv.set_cursor(path)
        return

    def auto_rename(self, new_auto_name):
        label = self.get_label()
        if label is None:
            return
        if self.last_auto_name is None:
            print "no last_auto_name"
            label.set_text(new_auto_name)
            self.last_auto_name = new_auto_name
            return
        current_name = label.get_text()
        if self.last_auto_name in current_name:
            if current_name != new_auto_name:
                print "setting new %r from old %r" % (new_auto_name,
                                                      current_name)
                label.set_text(
                    current_name.replace(self.last_auto_name, new_auto_name))
                self.last_auto_name = new_auto_name
        else:
            print "last auto name %r not in %r!" % (self.last_auto_name,
                                                    current_name)
        return

    def user_rename(self, new_name):
        # tab_widget = self.nb.get_tab_label(self.page)
        label = self.get_label()
        label.set_text(new_name)

    def destroy(self):
        # try to free some memory
        if self.model:
            self.model.clear()
        self.textview.get_buffer().set_text("")
        del self.treeview
        del self.model
        del self.textview
        self.treeview = None
        self.model = None
        self.textview = None
        self.update_db_label()

    def set(self, text):
        self.last_source = text
        self.textview.get_buffer().set_text(text)

    def update_db_label(self):
        h = self.current_host
        d = self.current_db
        if not h:
            self.query_db_label.set_label("no host/database selected")
            return
        title = "selected host"
        if d:
            dname = "/" + d.name
            title = "selected database"
        else:
            dname = ""
        if h.name == h.host:
            hname = h.name
        else:
            hname = "%s(%s)" % (h.name, h.host)

        self.query_db_label.set_label("%s: %s@%s%s" %
                                      (title, h.user, hname, dname))
        self.auto_rename("%s%s" % (h.name, dname))

    def set_current_host(self, host):
        if self.current_host == host and host is not None and self.current_db == host.current_db:
            return
        self.current_host = host
        if host:
            self.current_db = host.current_db
        else:
            self.current_db = None
        self.update_db_label()

    def set_current_db(self, db):
        self.current_host = db.host
        self.current_db = db
        self.update_db_label()

    def update_bottom_label(self):
        self.query_bottom_label.set_label("encoding: %s" % self.encoding)

    def set_query_encoding(self, encoding):
        self.encoding = encoding
        self.update_bottom_label()

    def set_query_font(self, font_name):
        self.textview.get_pango_context()
        fd = pango.FontDescription(font_name)
        self.textview.modify_font(fd)

    def set_result_font(self, font_name):
        self.treeview.get_pango_context()
        fd = pango.FontDescription(font_name)
        self.treeview.modify_font(fd)

    def set_wrap_mode(self, wrap):
        self.textview.set_wrap_mode(wrap)

    def on_rename_query_tab_clicked(self, button):
        label = self.get_label()
        new_name = dialogs.input_dialog(
            "Rename tab", "Please enter the new name of this tab:",
            label.get_text(), self.emma.mainwindow)
        if new_name is None:
            return
        if new_name == "":
            self.last_auto_name = None
            self.update_db_label()
            return
        self.user_rename(new_name)

    def on_closequery_button_clicked(self, button):
        self.emma.main_notebook.close_query_tab()

    def on_query_tab_label_close_button_clicked(self, button, page_index):
        print button, page_index
        self.emma.main_notebook.close_query_tab(page_index)

    def on_newquery_button_clicked(self, button):
        self.emma.main_notebook.add_query_tab()

    def on_query_font_clicked(self, button):
        d = self.emma.assign_once("query text font", gtk.FontSelectionDialog,
                                  "select query font")
        d.set_font_name(self.emma.config.get("query_text_font"))
        answer = d.run()
        d.hide()
        if not answer == gtk.RESPONSE_OK:
            return
        font_name = d.get_font_name()
        self.set_query_font(font_name)
        self.emma.config.config["query_text_font"] = font_name
        self.emma.config.save()

    def on_load_query_clicked(self, button):
        d = self.emma.assign_once("load dialog", gtk.FileChooserDialog,
                                  "Load query", self.emma.mainwindow,
                                  gtk.FILE_CHOOSER_ACTION_OPEN,
                                  (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                   gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT))

        d.set_default_response(gtk.RESPONSE_ACCEPT)
        answer = d.run()
        d.hide()
        if not answer == gtk.RESPONSE_ACCEPT:
            return

        filename = d.get_filename()
        try:
            sbuf = os.stat(filename)
        except:
            dialogs.show_message("Load query",
                                 "%s does not exists!" % filename)
            return
        if not S_ISREG(sbuf.st_mode):
            dialogs.show_message("Load query",
                                 "%s exists, but is not a file!" % filename)
            return

        size = sbuf.st_size
        _max = int(
            self.emma.config.get("ask_execute_query_from_disk_min_size"))
        if size > _max:
            if dialogs.confirm(
                    "load query", """
<b>%s</b> is very big (<b>%.2fMB</b>)!
opening it in the normal query-view may need a very long time!
if you just want to execute this skript file without editing and
syntax-highlighting, i can open this file using the <b>execute file from disk</b> function.
<b>shall i do this?</b>""" % (filename, size / 1024.0 / 1000.0),
                    self.emma.mainwindow):
                self.emma.on_execute_query_from_disk_activate(None, filename)
                return
        try:
            fp = file(filename, "rb")
            query_text = fp.read()
            fp.close()
        except:
            dialogs.show_message(
                "Load Query", "Error reading query from file %s: %s" %
                (filename, sys.exc_value))
            return
        self.textview.get_buffer().set_text(query_text)

    def on_save_query_clicked(self, button):
        d = self.emma.assign_once("save dialog", gtk.FileChooserDialog,
                                  "Save query", self.emma.mainwindow,
                                  gtk.FILE_CHOOSER_ACTION_SAVE,
                                  (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                   gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))

        d.set_default_response(gtk.RESPONSE_ACCEPT)
        answer = d.run()
        d.hide()
        if not answer == gtk.RESPONSE_ACCEPT:
            return
        filename = d.get_filename()
        if os.path.exists(filename):
            if not os.path.isfile(filename):
                dialogs.show_message(
                    "save query",
                    "%s already exists and is not a file!" % filename)
                return
            if not dialogs.confirm(
                    "Overwrite file?",
                    "%s already exists! Do you want to overwrite it?" %
                    filename, self.emma.mainwindow):
                return
        b = self.textview.get_buffer()
        query_text = b.get_text(b.get_start_iter(), b.get_end_iter())
        try:
            fp = file(filename, "wb")
            fp.write(query_text)
            fp.close()
        except:
            dialogs.show_message(
                "Save Query", "Error writing query to file %s: %s" %
                (filename, sys.exc_value))

    def on_execution_timeout(self, button):
        value = button.get_value()
        if value < 0.1:
            self.execution_timer_running = False
            return False
        if not self.on_execute_query_clicked():
            # stop on error
            button.set_value(0)
            value = 0
        if value != self.execution_timer_interval:
            self.execution_timer_running = False
            self.on_reexecution_spin_changed(button)
            return False
        return True

    def on_reexecution_spin_changed(self, button):
        value = button.get_value()
        if self.execution_timer_running:
            return
        self.execution_timer_running = True
        self.execution_timer_interval = value
        gobject.timeout_add(int(value * 1000), self.on_execution_timeout,
                            button)

    def on_execute_query_clicked(self, button=None, query=None):
        field_count = 0
        if not query:
            b = self.textview.get_buffer()
            text = b.get_text(b.get_start_iter(), b.get_end_iter())
        else:
            text = query

        self.current_host = host = self.current_host
        if not host:
            dialogs.show_message(
                "error executing this query!",
                "could not execute query, because there is no selected host!")
            return

        self.current_db = self.current_db
        if self.current_db:
            host.select_database(self.current_db)
        elif host.current_db:
            if not dialogs.confirm(
                    "query without selected db",
                    """warning: this query tab has no database selected
                    but the host-connection already has the database '%s' selected.
                    the author knows no way to deselect this database.
                    do you want to continue?""" % host.current_db.name,
                    self.emma.mainwindow):
                return

        update = False
        select = False
        self.editable = False
        # single popup
        self.add_record.set_sensitive(False)
        self.delete_record.set_sensitive(False)
        # per query buttons
        self.add_record.set_sensitive(False)
        self.delete_record.set_sensitive(False)
        self.apply_record.set_sensitive(False)
        self.local_search.set_sensitive(False)
        self.remove_order.set_sensitive(False)
        self.save_result.set_sensitive(False)
        self.save_result_sql.set_sensitive(False)

        affected_rows = 0
        last_insert_id = 0
        num_rows = 0

        query_time = 0
        download_time = 0
        display_time = 0
        query_count = 0
        total_start = time.time()

        # cleanup last query model and treeview
        for col in self.treeview.get_columns():
            self.treeview.remove_column(col)
        if self.model:
            self.model.clear()

        _start = 0
        while _start < len(text):
            # search query end
            query_start, end = read_query(text, _start)
            if query_start is None:
                break
            thisquery = text[query_start:end]
            print "about to execute query %r" % thisquery
            _start = end + 1

            thisquery.strip(" \r\n\t;")
            if not thisquery:
                continue  # empty query
            query_count += 1
            query_hint = re.sub("[\n\r\t ]+", " ", thisquery[:40])
            self.label.set_text("executing query %d %s..." %
                                (query_count, query_hint))
            self.label.window.process_updates(False)

            appendable = False
            appendable_result = is_query_appendable(thisquery)
            if appendable_result:
                appendable = True
                self.editable = self.is_query_editable(thisquery,
                                                       appendable_result)
            print "appendable: %s, editable: %s" % (appendable, self.editable)

            ret = host.query(thisquery, encoding=self.encoding)
            query_time += host.query_time

            # if stop on error is enabled
            if not ret:
                print "mysql error: %r" % (host.last_error, )
                message = "error at: %s" % host.last_error.replace(
                    "You have an error in your SQL syntax.  "
                    "Check the manual that corresponds to your MySQL server version for the right syntax to use near ",
                    "")
                message = "error at: %s" % message.replace(
                    "You have an error in your SQL syntax; "
                    "check the manual that corresponds to your MySQL server "
                    "version for the right syntax to use near ", "")

                line_pos = 0
                pos = message.find("at line ")
                if pos != -1:
                    line_no = int(message[pos + 8:])
                    while 1:
                        line_no -= 1
                        if line_no < 1:
                            break
                        p = thisquery.find("\n", line_pos)
                        if p == -1:
                            break
                        line_pos = p + 1

                i = self.textview.get_buffer().get_iter_at_offset(query_start +
                                                                  line_pos)

                match = re.search("error at: '(.*)'", message, re.DOTALL)
                if match and match.group(1):
                    # set focus and cursor!
                    #print "search for ->%s<-" % match.group(1)
                    pos = text.find(match.group(1), query_start + line_pos,
                                    query_start + len(thisquery))
                    if not pos == -1:
                        i.set_offset(pos)
                else:
                    match = re.match("Unknown column '(.*?')", message)
                    if match:
                        # set focus and cursor!
                        pos = thisquery.find(match.group(1))
                        if not pos == 1:
                            i.set_offset(query_start + pos)

                self.textview.get_buffer().place_cursor(i)
                self.textview.scroll_to_iter(i, 0.0)
                self.textview.grab_focus()
                self.label.set_text(re.sub("[\r\n\t ]+", " ", message))
                return

            field_count = host.handle.field_count()
            if field_count == 0:
                # query without result
                update = True
                affected_rows += host.handle.affected_rows()
                last_insert_id = host.handle.insert_id()
                continue

            # query with result
            self.append_iter = None
            self.local_search.set_sensitive(True)
            self.add_record.set_sensitive(appendable)
            self.delete_record.set_sensitive(self.editable)
            select = True
            self.last_source = thisquery
            # get sort order!
            sortable = True  # todo
            current_order = get_order_from_query(thisquery)
            sens = False
            if len(current_order) > 0:
                sens = True
            self.remove_order.set_sensitive(sens and sortable)

            sort_fields = dict()
            for c, o in current_order:
                sort_fields[c.lower()] = o
            self.label.set_text("downloading resultset...")
            self.label.window.process_updates(False)

            start_download = time.time()
            result = host.handle.store_result()
            download_time = time.time() - start_download
            if download_time < 0:
                download_time = 0

            self.label.set_text("displaying resultset...")
            self.label.window.process_updates(False)

            # store field info
            self.result_info = result.describe()
            num_rows = result.num_rows()

            for col in self.treeview.get_columns():
                self.treeview.remove_column(col)

            columns = [gobject.TYPE_STRING] * field_count
            self.model = gtk.ListStore(*columns)
            self.treeview.set_model(self.model)
            self.treeview.set_rules_hint(True)
            self.treeview.set_headers_clickable(True)
            for i in range(field_count):
                title = self.result_info[i][0].replace("_", "__").replace(
                    "[\r\n\t ]+", " ")
                text_renderer = gtk.CellRendererText()
                if self.editable:
                    text_renderer.set_property("editable", True)
                    text_renderer.connect("edited", self.on_query_change_data,
                                          i)
                l = self.treeview.insert_column_with_data_func(
                    -1, title, text_renderer,
                    widgets.ResultCellRenders.render_mysql_string, i)

                col = self.treeview.get_column(l - 1)

                if self.emma.config.get_bool("result_view_column_resizable"):
                    col.set_resizable(True)
                else:
                    col.set_resizable(False)
                    col.set_min_width(
                        int(
                            self.emma.config.get(
                                "result_view_column_width_min")))
                    col.set_max_width(
                        int(
                            self.emma.config.get(
                                "result_view_column_width_max")))

                if sortable:
                    col.set_clickable(True)
                    col.connect("clicked", self.on_query_column_sort, i)
                    # set sort indicator
                    field_name = self.result_info[i][0].lower()
                    try:
                        sort_col = sort_fields[field_name]
                        col.set_sort_indicator(True)
                        if sort_col:
                            col.set_sort_order(gtk.SORT_ASCENDING)
                        else:
                            col.set_sort_order(gtk.SORT_DESCENDING)
                    except:
                        col.set_sort_indicator(False)
                else:
                    col.set_clickable(False)
                    col.set_sort_indicator(False)

            cnt = 0
            start_display = time.time()
            last_display = start_display
            for row in result.fetch_row(0):

                def to_string(f):
                    if type(f) == str:
                        f = f.decode(self.encoding, "replace")
                    elif f is None:
                        pass
                    else:
                        f = str(f)
                    return f

                self.model.append(map(to_string, row))
                cnt += 1
                if not cnt % 100 == 0:
                    continue

                now = time.time()
                if (now - last_display) < 0.2:
                    continue

                self.label.set_text("displayed %d rows..." % cnt)
                self.label.window.process_updates(False)
                last_display = now

            display_time = time.time() - start_display
            if display_time < 0:
                display_time = 0

        result = []
        if select:
            # there was a query with a result
            result.append("rows: %d" % num_rows)
            result.append("fields: %d" % field_count)
            self.save_result.set_sensitive(True)
            self.save_result_sql.set_sensitive(True)
        if update:
            # there was a query without a result
            result.append("affected rows: %d" % affected_rows)
            result.append("insert_id: %d" % last_insert_id)
        total_time = time.time() - total_start
        result.append("| total time: %.2fs (query: %.2fs" %
                      (total_time, query_time))
        if select:
            result.append("download: %.2fs display: %.2fs" %
                          (download_time, display_time))
        result.append(")")

        self.label.set_text(' '.join(result))
        self.emma.blob_view.tv.set_editable(self.editable)
        self.emma.blob_view.blob_update.set_sensitive(self.editable)
        self.emma.blob_view.blob_load.set_sensitive(self.editable)
        # todo update_buttons()
        gc.collect()
        return True

    def is_query_editable(self, query, result=None):
        table, where, field, value, row_iter = self.get_unique_where(query)
        if not table or not where:
            return False
        return True

    def on_query_column_sort(self, column, col_num):
        query = self.last_source
        current_order = get_order_from_query(query)
        col = column.get_title().replace("__", "_")
        new_order = []
        for c, o in current_order:
            if c == col:
                if o:
                    new_order.append([col, False])
                col = None
            else:
                new_order.append([c, o])
        if col:
            new_order.append([self.current_host.escape_field(col), True])
        try:
            r = self.query_order_re
        except:
            r = self.query_order_re = re.compile(re_src_query_order)
        match = re.search(r, query)
        if match:
            before, order, after = match.groups()
            order = ""
            addition = ""
        else:
            match = re.search(re_src_after_order, query)
            if not match:
                before = query
                after = ""
            else:
                before = query[0:match.start()]
                after = match.group()
            addition = "\norder by\n\t"
        order = ""
        for col, o in new_order:
            if order:
                order += ",\n\t"
            order += self.current_host.escape_field(col)
            if not o:
                order += " desc"
        if order:
            new_query = ''.join([before, addition, order, after])
        else:
            new_query = re.sub("(?i)order[ \r\n\t]+by[ \r\n\t]+", "",
                               before + after)
        self.set(new_query)

        if self.emma.config.get("result_view_column_sort_timeout") <= 0:
            self.on_execute_query_clicked()

        new_order = dict(new_order)

        for col in self.treeview.get_columns():
            field_name = col.get_title().replace("__", "_")
            try:
                sort_col = new_order[field_name]
                col.set_sort_indicator(True)
                if sort_col:
                    col.set_sort_order(gtk.SORT_ASCENDING)
                else:
                    col.set_sort_order(gtk.SORT_DESCENDING)
            except:
                col.set_sort_indicator(False)

        if not self.sort_timer_running:
            self.sort_timer_running = True
            gobject.timeout_add(
                100 +
                int(self.emma.config.get("result_view_column_sort_timeout")),
                self.on_sort_timer)
        self.sort_timer_execute = time.time() + int(
            self.emma.config.get("result_view_column_sort_timeout")) / 1000.

    def get_unique_where(self,
                         query,
                         path=None,
                         col_num=None,
                         return_fields=False):
        # call is_query_appendable before!
        result = is_query_appendable(query)
        if not result:
            return None, None, None, None, None

        field_list = result.group(6)
        table_list = result.group(7)

        # check tables
        table_list = table_list.replace(" join ", ",")
        table_list = re.sub(
            "(?i)(?:order[ \t\r\n]by.*|limit.*|group[ \r\n\t]by.*|order[ \r\n\t]by.*|where.*)",
            "", table_list)
        table_list = table_list.replace("`", "")
        tables = table_list.split(",")

        if len(tables) > 1:
            print "sorry, i can't edit queries with more than one source-table:", tables
            return None, None, None, None, None

        # get table_name
        table = tables[0].strip(" \r\n\t").strip("`'\"")
        print "table:", table

        # check for valid fields
        field_list = re.sub("[\r\n\t ]+", " ", field_list)
        field_list = re.sub("'.*?'", "__BAD__STRINGLITERAL", field_list)
        field_list = re.sub("\".*?\"", "__BAD__STRINGLITERAL", field_list)
        field_list = re.sub("\\(.*?\\)", "__BAD__FUNCTIONARGUMENTS",
                            field_list)
        field_list = re.sub("\\|", "__PIPE__", field_list)
        temp_fields = field_list.split(",")
        fields = []
        for f in temp_fields:
            fields.append(f.strip("` \r\n\t"))
        print "fields:", fields

        wildcard = False
        for db_field_object in fields:
            if db_field_object.find("*") != -1:
                wildcard = True
                break

        # find table handle!
        th = None
        tries = 0
        new_tables = []
        self.last_th = None
        if not self.current_host:
            print "Host not selected"
            return None, None, None, None, None
        if not self.current_host.current_db:
            print "Database not selected"
            return None, None, None, None, None
        while 1:
            try:
                th = self.current_host.current_db.tables[table]
                break
            except:
                tries += 1
                if tries > 1:
                    print "query not editable, because table %r is not found in db %r" % (
                        table, self.current_host.current_db)
                    return None, None, None, None, None
                new_tables = self.current_host.current_db.refresh()
                continue
        # does this field really exist in this table?
        c = 0
        possible_primary = possible_unique = ""
        unique = primary = ""
        pri_okay = uni_okay = 0

        for i in new_tables:
            self.current_host.current_db.tables[i].refresh(False)

        if not th.fields and not table in new_tables:
            th.refresh(False)

        row_iter = None
        if path:
            row_iter = self.model.get_iter(path)

        # get unique where_clause
        self.kv_list = []
        self.last_th = th
        field_pos = 0
        for db_field_object in th.fields:
            if ((pri_okay >= 0 and db_field_object.row['Key'] == "PRI")
                    or (th.host.__class__.__name__ == "sqlite_host"
                        and db_field_object.name.endswith("_id"))):
                if possible_primary:
                    possible_primary += ", "
                possible_primary += db_field_object.name
                if wildcard:
                    c = field_pos
                else:
                    c = None
                    try:
                        c = fields.index(db_field_object.name)
                    except:
                        pass
                if not c is None:
                    pri_okay = 1
                    if path:
                        value = self.model.get_value(row_iter, c)
                        if primary:
                            primary += " and "
                        primary += "`%s`='%s'" % (db_field_object.name, value)
                        self.kv_list.append((db_field_object.name, value))
            if uni_okay >= 0 and db_field_object.row['Key'] == "UNI":
                if possible_unique:
                    possible_unique += ", "
                possible_unique += db_field_object.name
                if wildcard:
                    c = field_pos
                else:
                    c = None
                    try:
                        c = fields.index(db_field_object.name)
                    except:
                        pass
                if not c is None:
                    uni_okay = 1
                    if path:
                        value = self.model.get_value(row_iter, c)
                        if unique:
                            unique += " and "
                        unique += "`%s`='%s'" % (db_field_object.name, value)
                        self.kv_list.append((db_field_object.name, value))
            field_pos += 1

        if uni_okay < 1 and pri_okay < 1:
            possible_key = "(i can't see any key-fields in this table...)"
            if possible_primary:
                possible_key = "e.g.'%s' would be useful!" % possible_primary
            elif possible_unique:
                possible_key = "e.g.'%s' would be useful!" % possible_unique
            print "no edit-key found. try to name a key-field in your select-clause. (%r)" % possible_key
            return table, None, None, None, None

        value = ""
        db_field_object = None
        if path:
            where = primary
            if not where:
                where = unique
            if not where:
                where = None
            if not col_num is None:
                value = self.model.get_value(row_iter, col_num)
                if wildcard:
                    db_field_object = th.field_order[col_num]
                else:
                    db_field_object = fields[col_num]
        else:
            where = possible_primary + possible_unique

        # get current edited field and value by col_num
        if return_fields:
            return table, where, db_field_object, value, row_iter, fields
        return table, where, db_field_object, value, row_iter

    def on_query_change_data(self,
                             cellrenderer,
                             path,
                             new_value,
                             col_num,
                             force_update=False):
        row_iter = self.model.get_iter(path)
        if self.append_iter \
                and self.model.iter_is_valid(self.append_iter) \
                and self.model.get_path(self.append_iter) == self.model.get_path(row_iter):
            self.filled_fields[self.treeview.get_column(
                col_num).get_title().replace("__", "_")] = new_value
            self.model.set_value(row_iter, col_num, new_value)
            return

        table, where, field, value, row_iter = self.get_unique_where(
            self.last_source, path, col_num)
        if force_update is False and new_value == value:
            return
        if self.current_host.__class__.__name__ == "sqlite_host":
            limit = ""
        else:
            limit = " limit 1"
        update_query = u"update %s set %s='%s' where %s%s" % (
            self.current_host.escape_table(table),
            self.current_host.escape_field(field),
            self.current_host.escape(new_value), where, limit)
        if self.current_host.query(update_query, encoding=self.encoding):
            print "set new value: %r" % new_value
            self.model.set_value(row_iter, col_num, new_value)
            return True
        return False

    def on_sort_timer(self):
        if not self.sort_timer_running:
            return False
        if self.sort_timer_execute > time.time():
            return True
        self.sort_timer_running = False
        self.on_execute_query_clicked()
        return False

    def get_ui(self):
        return self.ui
Пример #4
0
class QueryTab(widgets.BaseTab):
    def __init__(self, emma):
        """
        @param emma: Emma
        """
        super(QueryTab, self).__init__()
        self.xml = gtk.glade.XML(os.path.join(emma.glade_path, "querytab.glade"), "first_query")
        self.xml.signal_autoconnect(self)

        self.tab_label.set_text("Query")
        self.tab_label_icon.set_from_file(os.path.join(icons_path, "page_code.png"))

        self.emma = emma

        self.save_result = self.xml.get_widget("save_result")
        self.save_result_sql = self.xml.get_widget("save_result_sql")
        self.local_search = self.xml.get_widget("local_search_button")
        self.remove_order = self.xml.get_widget("remove_order")

        self.label = self.xml.get_widget("query_label")

        self.add_record = self.xml.get_widget("add_record_tool")
        self.delete_record = self.xml.get_widget("delete_record_tool")

        self.query_bottom_label = self.xml.get_widget("query_bottom_label")
        self.query_db_label = self.xml.get_widget("query_db_label")

        self.textview = self.xml.get_widget("query_text")

        self.query_text_sw = self.xml.get_widget("query_text_sw")
        self.apply_record = self.xml.get_widget("apply_record_tool")
        self.ui = self.xml.get_widget("first_query")
        self.toolbar = self.xml.get_widget("inner_query_toolbar")
        self.toolbar.set_style(gtk.TOOLBAR_ICONS)

        self.scrolledwindow6 = self.xml.get_widget("scrolledwindow6")
        self.treeview = QueryTabTreeView(emma)
        self.scrolledwindow6.add(self.treeview)
        self.treeview.show()

        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        self.treeview.connect("cursor_changed", self.on_query_view_cursor_changed)
        # todo: move to keymap
        self.treeview.connect("key_press_event", self.on_query_view_key_press_event)
        self.treeview.connect("button_press_event", self.on_query_view_button_press_event)

        self.execution_timer_running = False
        self.execution_timer_interval = 0
        self.editable = False

        self.sort_timer_running = False
        self.sort_timer_execute = 0

        self.query_encoding_menu = None

        self.filled_fields = []

        # replace textview with gtksourcevice
        try:
            org_tv = self.textview
            manager = gtksourceview2.language_manager_get_default()
            language = manager.get_language("sql")

            sb = gtksourceview2.Buffer()
            sb.set_highlight_syntax(True)
            sb.set_language(language)
            sv = self.textview = gtksourceview2.View(sb)

            self.query_text_sw.remove(org_tv)
            self.query_text_sw.add(sv)
            sv.show()

            sv.set_show_line_numbers(True)
            sv.set_show_line_marks(True)
            sv.set_tab_width(4)
            sv.set_auto_indent(True)
            sv.set_insert_spaces_instead_of_tabs(False)
            sv.set_show_right_margin(True)
            sv.set_smart_home_end(True)
            sv.set_right_margin_position(80)

            # sv config
            # for pt, pn, pd in (
            #     (bool, "show_line_numbers", True),
            #     #(bool, "show_line_markers", False),
            #     #(int, "tabs_width", 4),
            #     (bool, "auto_indent", True),
            #     (bool, "insert_spaces_instead_of_tabs", False),
            #     #(bool, "show_margin", True),
            #     #(int, "margin", 80),
            #     (bool, "smart_home_end", True)
            # ):
            #
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sv, "set_%s" % pn)
            #     method(v)
            # sb config
            # for pt, pn, pd in (
            #     (bool, "check_brackets", True),
            #     (bool, "highlight", True),
            #     (int, "max_undo_levels", 15)
            # ):
            #     cn = "sourceview.%s" % pn
            #     try:
            #         v = self.emma.config[cn]
            #         if pt == bool:
            #             v = v == "1" or v.lower() == "true" or v.lower() == "yes"
            #         else:
            #             v = pt(v)
            #     except:
            #         v = pd
            #     method = getattr(sb, "set_%s" % pn)
            #     method(v)
        except:
            dialogs.alert(traceback.format_exc())

        self.current_host = None
        self.current_db = None
        self.model = None
        self.last_source = None
        self.result_info = None
        self.append_iter = None
        self.last_path = None
        self.encoding = None
        if hasattr(self, "query"):
            self.textview.get_buffer().set_text(self.query)
        self.last_auto_name = None

        #
        #   INIT Query tab actions
        #

        self.remember_order_action = QueryTabRememberOrder(self, emma)
        self.remove_order_action = QueryTabRemoveOrder(self, emma)
        self.set_result_font_action = QueryTabSetResultFont(self, emma)
        self.local_search_action = QueryTabLocalSearch(self, emma)
        self.save_result_sql_action = QueryTabSaveResultSql(self, emma)
        self.save_result_csv_action = QueryTabSaveResultCsv(self, emma)
        self.manage_row_action = QueryTabManageRow(self, emma)

        #
        #
        #

        self.emma.key_map.connect("key-release", self.key_release)
        self.init_from_config()

    def init_from_config(self):
        self.set_query_encoding(self.emma.config.get("db_encoding"))
        self.set_query_font(self.emma.config.get("query_text_font"))
        self.set_result_font(self.emma.config.get("query_result_font"))
        if self.emma.config.get_bool("query_text_wrap"):
            self.set_wrap_mode(gtk.WRAP_WORD)
        else:
            self.set_wrap_mode(gtk.WRAP_NONE)
        self.set_current_host(self.emma.current_host)

    def key_release(self, key_map, event):
        pass

    def on_query_view_cursor_changed(self, tv):
        self.emma.blob_view.encoding = self.encoding
        path, column = self.treeview.get_cursor()

        if not path:
            return

        _iter = self.model.get_iter(path)
        if column is not None:
            col = self.treeview.get_columns().index(column)
        else:
            col = 0
        value = self.model.get_value(_iter, col)
        if value is None:
            # todo signal null value
            self.emma.blob_view.buffer.set_text("")
        else:
            self.emma.blob_view.buffer.set_text(value)
        self.emma.blob_view.tv.set_sensitive(True)

        if self.append_iter:
            if path == self.model.get_path(self.append_iter):
                return
            self.manage_row_action.on_apply_record_tool_clicked(None)

    # todo: move to keymap
    def on_query_view_key_press_event(self, tv, event):
        path, column = self.treeview.get_cursor()
        if event.keyval == keysyms.F2:
            self.treeview.set_cursor(path, column, True)
            return True

        if not self.model:
            return False

        _iter = self.model.get_iter(path)
        if event.keyval == keysyms.Down and not self.model.iter_next(_iter):
            if self.append_iter and not self.manage_row_action.on_apply_record_tool_clicked(None):
                return True
            self.manage_row_action.on_add_record_tool_clicked(None)
            return True

    def on_query_view_button_press_event(self, tv, event):
        selection = tv.get_selection()

        print selection.get_selected_rows()

        if event.button != 3 or selection.count_selected_rows() == 0:
            return False

        is_single_row = selection.count_selected_rows() == 1

        menu = QueryTabResultPopup(self, is_single_row)

        menu.popup(None, None, None, 0, 0)  # strange!
        #
        #   If selection is single row - let change row focus
        #
        if is_single_row:
            return False
        else:
            return True

    def on_query_bottom_eventbox_button_press_event(self, ebox, event):
        if not self.query_encoding_menu:
            self.query_encoding_menu = QueryTabPopupEncoding(self)
        self.query_encoding_menu.popup(None, None, None, event.button, event.time)

    def on_query_db_eventbox_button_press_event(self, ebox, event):
        q = self
        host = q.current_host
        db = q.current_db
        if q.last_path is not None:
            try:
                self.emma.connections_tv.connections_model.get_iter(q.last_path)
                self.emma.connections_tv.set_cursor(q.last_path)
                return
            except:
                # path was not valid
                pass

        i = self.emma.connections_tv.connections_model.get_iter_root()
        while i and self.emma.connections_tv.connections_model.iter_is_valid(i):
            if self.emma.connections_tv.connections_model[i][0] == host:
                break
            i = self.emma.connections_tv.connections_model.iter_next(i)
        else:
            print "host not found in connections list!"
            q.current_host = q.current_db = None
            q.update_db_label()
            return

        host_path = self.emma.connections_tv.connections_model.get_path(i)
        self.emma.connections_tv.scroll_to_cell(host_path, column=None, use_align=True, row_align=0.0, col_align=0.0)
        if db is None:
            self.emma.connections_tv.set_cursor(host_path)
            return
        k = self.emma.connections_tv.connections_model.iter_children(i)
        while k and self.emma.connections_tv.connections_model.iter_is_valid(k):
            if self.emma.connections_tv.connections_model[k][0] == db:
                break
            k = self.emma.connections_tv.connections_model.iter_next(k)
        else:
            print "database not found in connections list!"
            q.current_db = None
            q.update_db_label()
            self.emma.connections_tv.set_cursor(host_path)
            return
        path = self.emma.connections_tv.connections_model.get_path(k)
        # self.connections_tv.scroll_to_cell(path, column=None, use_align=True, row_align=0.125, col_align=0.0)
        self.emma.connections_tv.set_cursor(path)
        return

    def auto_rename(self, new_auto_name):
        label = self.get_label()
        if label is None:
            return
        if self.last_auto_name is None:
            print "no last_auto_name"
            label.set_text(new_auto_name)
            self.last_auto_name = new_auto_name
            return
        current_name = label.get_text()
        if self.last_auto_name in current_name:
            if current_name != new_auto_name:
                print "setting new %r from old %r" % (new_auto_name, current_name)
                label.set_text(current_name.replace(self.last_auto_name, new_auto_name))
                self.last_auto_name = new_auto_name
        else:
            print "last auto name %r not in %r!" % (self.last_auto_name, current_name)
        return

    def user_rename(self, new_name):
        # tab_widget = self.nb.get_tab_label(self.page)
        label = self.get_label()
        label.set_text(new_name)

    def destroy(self):
        # try to free some memory
        if self.model:
            self.model.clear()
        self.textview.get_buffer().set_text("")
        del self.treeview
        del self.model
        del self.textview
        self.treeview = None
        self.model = None
        self.textview = None
        self.update_db_label()

    def set(self, text):
        self.last_source = text
        self.textview.get_buffer().set_text(text)

    def update_db_label(self):
        h = self.current_host
        d = self.current_db
        if not h:
            self.query_db_label.set_label("no host/database selected")
            return
        title = "selected host"
        if d:
            dname = "/" + d.name
            title = "selected database"
        else:
            dname = ""
        if h.name == h.host:
            hname = h.name
        else:
            hname = "%s(%s)" % (h.name, h.host)

        self.query_db_label.set_label("%s: %s@%s%s" % (title, h.user, hname, dname))
        self.auto_rename("%s%s" % (h.name, dname))

    def set_current_host(self, host):
        if self.current_host == host and host is not None and self.current_db == host.current_db:
            return
        self.current_host = host
        if host:
            self.current_db = host.current_db
        else:
            self.current_db = None
        self.update_db_label()

    def set_current_db(self, db):
        self.current_host = db.host
        self.current_db = db
        self.update_db_label()

    def update_bottom_label(self):
        self.query_bottom_label.set_label("encoding: %s" % self.encoding)

    def set_query_encoding(self, encoding):
        self.encoding = encoding
        self.update_bottom_label()

    def set_query_font(self, font_name):
        self.textview.get_pango_context()
        fd = pango.FontDescription(font_name)
        self.textview.modify_font(fd)

    def set_result_font(self, font_name):
        self.treeview.get_pango_context()
        fd = pango.FontDescription(font_name)
        self.treeview.modify_font(fd)

    def set_wrap_mode(self, wrap):
        self.textview.set_wrap_mode(wrap)

    def on_rename_query_tab_clicked(self, button):
        label = self.get_label()
        new_name = dialogs.input_dialog(
            "Rename tab", "Please enter the new name of this tab:", label.get_text(), self.emma.mainwindow
        )
        if new_name is None:
            return
        if new_name == "":
            self.last_auto_name = None
            self.update_db_label()
            return
        self.user_rename(new_name)

    def on_closequery_button_clicked(self, button):
        self.emma.main_notebook.close_query_tab()

    def on_query_tab_label_close_button_clicked(self, button, page_index):
        print button, page_index
        self.emma.main_notebook.close_query_tab(page_index)

    def on_newquery_button_clicked(self, button):
        self.emma.main_notebook.add_query_tab()

    def on_query_font_clicked(self, button):
        d = self.emma.assign_once("query text font", gtk.FontSelectionDialog, "select query font")
        d.set_font_name(self.emma.config.get("query_text_font"))
        answer = d.run()
        d.hide()
        if not answer == gtk.RESPONSE_OK:
            return
        font_name = d.get_font_name()
        self.set_query_font(font_name)
        self.emma.config.config["query_text_font"] = font_name
        self.emma.config.save()

    def on_load_query_clicked(self, button):
        d = self.emma.assign_once(
            "load dialog",
            gtk.FileChooserDialog,
            "Load query",
            self.emma.mainwindow,
            gtk.FILE_CHOOSER_ACTION_OPEN,
            (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT),
        )

        d.set_default_response(gtk.RESPONSE_ACCEPT)
        answer = d.run()
        d.hide()
        if not answer == gtk.RESPONSE_ACCEPT:
            return

        filename = d.get_filename()
        try:
            sbuf = os.stat(filename)
        except:
            dialogs.show_message("Load query", "%s does not exists!" % filename)
            return
        if not S_ISREG(sbuf.st_mode):
            dialogs.show_message("Load query", "%s exists, but is not a file!" % filename)
            return

        size = sbuf.st_size
        _max = int(self.emma.config.get("ask_execute_query_from_disk_min_size"))
        if size > _max:
            if dialogs.confirm(
                "load query",
                """
<b>%s</b> is very big (<b>%.2fMB</b>)!
opening it in the normal query-view may need a very long time!
if you just want to execute this skript file without editing and
syntax-highlighting, i can open this file using the <b>execute file from disk</b> function.
<b>shall i do this?</b>"""
                % (filename, size / 1024.0 / 1000.0),
                self.emma.mainwindow,
            ):
                self.emma.on_execute_query_from_disk_activate(None, filename)
                return
        try:
            fp = file(filename, "rb")
            query_text = fp.read()
            fp.close()
        except:
            dialogs.show_message("Load Query", "Error reading query from file %s: %s" % (filename, sys.exc_value))
            return
        self.textview.get_buffer().set_text(query_text)

    def on_save_query_clicked(self, button):
        d = self.emma.assign_once(
            "save dialog",
            gtk.FileChooserDialog,
            "Save query",
            self.emma.mainwindow,
            gtk.FILE_CHOOSER_ACTION_SAVE,
            (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT),
        )

        d.set_default_response(gtk.RESPONSE_ACCEPT)
        answer = d.run()
        d.hide()
        if not answer == gtk.RESPONSE_ACCEPT:
            return
        filename = d.get_filename()
        if os.path.exists(filename):
            if not os.path.isfile(filename):
                dialogs.show_message("save query", "%s already exists and is not a file!" % filename)
                return
            if not dialogs.confirm(
                "Overwrite file?", "%s already exists! Do you want to overwrite it?" % filename, self.emma.mainwindow
            ):
                return
        b = self.textview.get_buffer()
        query_text = b.get_text(b.get_start_iter(), b.get_end_iter())
        try:
            fp = file(filename, "wb")
            fp.write(query_text)
            fp.close()
        except:
            dialogs.show_message("Save Query", "Error writing query to file %s: %s" % (filename, sys.exc_value))

    def on_execution_timeout(self, button):
        value = button.get_value()
        if value < 0.1:
            self.execution_timer_running = False
            return False
        if not self.on_execute_query_clicked():
            # stop on error
            button.set_value(0)
            value = 0
        if value != self.execution_timer_interval:
            self.execution_timer_running = False
            self.on_reexecution_spin_changed(button)
            return False
        return True

    def on_reexecution_spin_changed(self, button):
        value = button.get_value()
        if self.execution_timer_running:
            return
        self.execution_timer_running = True
        self.execution_timer_interval = value
        gobject.timeout_add(int(value * 1000), self.on_execution_timeout, button)

    def on_execute_query_clicked(self, button=None, query=None):
        field_count = 0
        if not query:
            b = self.textview.get_buffer()
            text = b.get_text(b.get_start_iter(), b.get_end_iter())
        else:
            text = query

        self.current_host = host = self.current_host
        if not host:
            dialogs.show_message(
                "error executing this query!", "could not execute query, because there is no selected host!"
            )
            return

        self.current_db = self.current_db
        if self.current_db:
            host.select_database(self.current_db)
        elif host.current_db:
            if not dialogs.confirm(
                "query without selected db",
                """warning: this query tab has no database selected
                    but the host-connection already has the database '%s' selected.
                    the author knows no way to deselect this database.
                    do you want to continue?"""
                % host.current_db.name,
                self.emma.mainwindow,
            ):
                return

        update = False
        select = False
        self.editable = False
        # single popup
        self.add_record.set_sensitive(False)
        self.delete_record.set_sensitive(False)
        # per query buttons
        self.add_record.set_sensitive(False)
        self.delete_record.set_sensitive(False)
        self.apply_record.set_sensitive(False)
        self.local_search.set_sensitive(False)
        self.remove_order.set_sensitive(False)
        self.save_result.set_sensitive(False)
        self.save_result_sql.set_sensitive(False)

        affected_rows = 0
        last_insert_id = 0
        num_rows = 0

        query_time = 0
        download_time = 0
        display_time = 0
        query_count = 0
        total_start = time.time()

        # cleanup last query model and treeview
        for col in self.treeview.get_columns():
            self.treeview.remove_column(col)
        if self.model:
            self.model.clear()

        _start = 0
        while _start < len(text):
            # search query end
            query_start, end = read_query(text, _start)
            if query_start is None:
                break
            thisquery = text[query_start:end]
            print "about to execute query %r" % thisquery
            _start = end + 1

            thisquery.strip(" \r\n\t;")
            if not thisquery:
                continue  # empty query
            query_count += 1
            query_hint = re.sub("[\n\r\t ]+", " ", thisquery[:40])
            self.label.set_text("executing query %d %s..." % (query_count, query_hint))
            self.label.window.process_updates(False)

            appendable = False
            appendable_result = is_query_appendable(thisquery)
            if appendable_result:
                appendable = True
                self.editable = self.is_query_editable(thisquery, appendable_result)
            print "appendable: %s, editable: %s" % (appendable, self.editable)

            ret = host.query(thisquery, encoding=self.encoding)
            query_time += host.query_time

            # if stop on error is enabled
            if not ret:
                print "mysql error: %r" % (host.last_error,)
                message = "error at: %s" % host.last_error.replace(
                    "You have an error in your SQL syntax.  "
                    "Check the manual that corresponds to your MySQL server version for the right syntax to use near ",
                    "",
                )
                message = "error at: %s" % message.replace(
                    "You have an error in your SQL syntax; "
                    "check the manual that corresponds to your MySQL server "
                    "version for the right syntax to use near ",
                    "",
                )

                line_pos = 0
                pos = message.find("at line ")
                if pos != -1:
                    line_no = int(message[pos + 8 :])
                    while 1:
                        line_no -= 1
                        if line_no < 1:
                            break
                        p = thisquery.find("\n", line_pos)
                        if p == -1:
                            break
                        line_pos = p + 1

                i = self.textview.get_buffer().get_iter_at_offset(query_start + line_pos)

                match = re.search("error at: '(.*)'", message, re.DOTALL)
                if match and match.group(1):
                    # set focus and cursor!
                    # print "search for ->%s<-" % match.group(1)
                    pos = text.find(match.group(1), query_start + line_pos, query_start + len(thisquery))
                    if not pos == -1:
                        i.set_offset(pos)
                else:
                    match = re.match("Unknown column '(.*?')", message)
                    if match:
                        # set focus and cursor!
                        pos = thisquery.find(match.group(1))
                        if not pos == 1:
                            i.set_offset(query_start + pos)

                self.textview.get_buffer().place_cursor(i)
                self.textview.scroll_to_iter(i, 0.0)
                self.textview.grab_focus()
                self.label.set_text(re.sub("[\r\n\t ]+", " ", message))
                return

            field_count = host.handle.field_count()
            if field_count == 0:
                # query without result
                update = True
                affected_rows += host.handle.affected_rows()
                last_insert_id = host.handle.insert_id()
                continue

            # query with result
            self.append_iter = None
            self.local_search.set_sensitive(True)
            self.add_record.set_sensitive(appendable)
            self.delete_record.set_sensitive(self.editable)
            select = True
            self.last_source = thisquery
            # get sort order!
            sortable = True  # todo
            current_order = get_order_from_query(thisquery)
            sens = False
            if len(current_order) > 0:
                sens = True
            self.remove_order.set_sensitive(sens and sortable)

            sort_fields = dict()
            for c, o in current_order:
                sort_fields[c.lower()] = o
            self.label.set_text("downloading resultset...")
            self.label.window.process_updates(False)

            start_download = time.time()
            result = host.handle.store_result()
            download_time = time.time() - start_download
            if download_time < 0:
                download_time = 0

            self.label.set_text("displaying resultset...")
            self.label.window.process_updates(False)

            # store field info
            self.result_info = result.describe()
            num_rows = result.num_rows()

            for col in self.treeview.get_columns():
                self.treeview.remove_column(col)

            columns = [gobject.TYPE_STRING] * field_count
            self.model = gtk.ListStore(*columns)
            self.treeview.set_model(self.model)
            self.treeview.set_rules_hint(True)
            self.treeview.set_headers_clickable(True)
            for i in range(field_count):
                title = self.result_info[i][0].replace("_", "__").replace("[\r\n\t ]+", " ")
                text_renderer = gtk.CellRendererText()
                if self.editable:
                    text_renderer.set_property("editable", True)
                    text_renderer.connect("edited", self.on_query_change_data, i)
                l = self.treeview.insert_column_with_data_func(
                    -1, title, text_renderer, widgets.ResultCellRenders.render_mysql_string, i
                )

                col = self.treeview.get_column(l - 1)

                if self.emma.config.get_bool("result_view_column_resizable"):
                    col.set_resizable(True)
                else:
                    col.set_resizable(False)
                    col.set_min_width(int(self.emma.config.get("result_view_column_width_min")))
                    col.set_max_width(int(self.emma.config.get("result_view_column_width_max")))

                if sortable:
                    col.set_clickable(True)
                    col.connect("clicked", self.on_query_column_sort, i)
                    # set sort indicator
                    field_name = self.result_info[i][0].lower()
                    try:
                        sort_col = sort_fields[field_name]
                        col.set_sort_indicator(True)
                        if sort_col:
                            col.set_sort_order(gtk.SORT_ASCENDING)
                        else:
                            col.set_sort_order(gtk.SORT_DESCENDING)
                    except:
                        col.set_sort_indicator(False)
                else:
                    col.set_clickable(False)
                    col.set_sort_indicator(False)

            cnt = 0
            start_display = time.time()
            last_display = start_display
            for row in result.fetch_row(0):

                def to_string(f):
                    if type(f) == str:
                        f = f.decode(self.encoding, "replace")
                    elif f is None:
                        pass
                    else:
                        f = str(f)
                    return f

                self.model.append(map(to_string, row))
                cnt += 1
                if not cnt % 100 == 0:
                    continue

                now = time.time()
                if (now - last_display) < 0.2:
                    continue

                self.label.set_text("displayed %d rows..." % cnt)
                self.label.window.process_updates(False)
                last_display = now

            display_time = time.time() - start_display
            if display_time < 0:
                display_time = 0

        result = []
        if select:
            # there was a query with a result
            result.append("rows: %d" % num_rows)
            result.append("fields: %d" % field_count)
            self.save_result.set_sensitive(True)
            self.save_result_sql.set_sensitive(True)
        if update:
            # there was a query without a result
            result.append("affected rows: %d" % affected_rows)
            result.append("insert_id: %d" % last_insert_id)
        total_time = time.time() - total_start
        result.append("| total time: %.2fs (query: %.2fs" % (total_time, query_time))
        if select:
            result.append("download: %.2fs display: %.2fs" % (download_time, display_time))
        result.append(")")

        self.label.set_text(" ".join(result))
        self.emma.blob_view.tv.set_editable(self.editable)
        self.emma.blob_view.blob_update.set_sensitive(self.editable)
        self.emma.blob_view.blob_load.set_sensitive(self.editable)
        # todo update_buttons()
        gc.collect()
        return True

    def is_query_editable(self, query, result=None):
        table, where, field, value, row_iter = self.get_unique_where(query)
        if not table or not where:
            return False
        return True

    def on_query_column_sort(self, column, col_num):
        query = self.last_source
        current_order = get_order_from_query(query)
        col = column.get_title().replace("__", "_")
        new_order = []
        for c, o in current_order:
            if c == col:
                if o:
                    new_order.append([col, False])
                col = None
            else:
                new_order.append([c, o])
        if col:
            new_order.append([self.current_host.escape_field(col), True])
        try:
            r = self.query_order_re
        except:
            r = self.query_order_re = re.compile(re_src_query_order)
        match = re.search(r, query)
        if match:
            before, order, after = match.groups()
            order = ""
            addition = ""
        else:
            match = re.search(re_src_after_order, query)
            if not match:
                before = query
                after = ""
            else:
                before = query[0 : match.start()]
                after = match.group()
            addition = "\norder by\n\t"
        order = ""
        for col, o in new_order:
            if order:
                order += ",\n\t"
            order += self.current_host.escape_field(col)
            if not o:
                order += " desc"
        if order:
            new_query = "".join([before, addition, order, after])
        else:
            new_query = re.sub("(?i)order[ \r\n\t]+by[ \r\n\t]+", "", before + after)
        self.set(new_query)

        if self.emma.config.get("result_view_column_sort_timeout") <= 0:
            self.on_execute_query_clicked()

        new_order = dict(new_order)

        for col in self.treeview.get_columns():
            field_name = col.get_title().replace("__", "_")
            try:
                sort_col = new_order[field_name]
                col.set_sort_indicator(True)
                if sort_col:
                    col.set_sort_order(gtk.SORT_ASCENDING)
                else:
                    col.set_sort_order(gtk.SORT_DESCENDING)
            except:
                col.set_sort_indicator(False)

        if not self.sort_timer_running:
            self.sort_timer_running = True
            gobject.timeout_add(100 + int(self.emma.config.get("result_view_column_sort_timeout")), self.on_sort_timer)
        self.sort_timer_execute = time.time() + int(self.emma.config.get("result_view_column_sort_timeout")) / 1000.0

    def get_unique_where(self, query, path=None, col_num=None, return_fields=False):
        # call is_query_appendable before!
        result = is_query_appendable(query)
        if not result:
            return None, None, None, None, None

        field_list = result.group(6)
        table_list = result.group(7)

        # check tables
        table_list = table_list.replace(" join ", ",")
        table_list = re.sub(
            "(?i)(?:order[ \t\r\n]by.*|limit.*|group[ \r\n\t]by.*|order[ \r\n\t]by.*|where.*)", "", table_list
        )
        table_list = table_list.replace("`", "")
        tables = table_list.split(",")

        if len(tables) > 1:
            print "sorry, i can't edit queries with more than one source-table:", tables
            return None, None, None, None, None

        # get table_name
        table = tables[0].strip(" \r\n\t").strip("`'\"")
        print "table:", table

        # check for valid fields
        field_list = re.sub("[\r\n\t ]+", " ", field_list)
        field_list = re.sub("'.*?'", "__BAD__STRINGLITERAL", field_list)
        field_list = re.sub('".*?"', "__BAD__STRINGLITERAL", field_list)
        field_list = re.sub("\\(.*?\\)", "__BAD__FUNCTIONARGUMENTS", field_list)
        field_list = re.sub("\\|", "__PIPE__", field_list)
        temp_fields = field_list.split(",")
        fields = []
        for f in temp_fields:
            fields.append(f.strip("` \r\n\t"))
        print "fields:", fields

        wildcard = False
        for db_field_object in fields:
            if db_field_object.find("*") != -1:
                wildcard = True
                break

        # find table handle!
        th = None
        tries = 0
        new_tables = []
        self.last_th = None
        if not self.current_host:
            print "Host not selected"
            return None, None, None, None, None
        if not self.current_host.current_db:
            print "Database not selected"
            return None, None, None, None, None
        while 1:
            try:
                th = self.current_host.current_db.tables[table]
                break
            except:
                tries += 1
                if tries > 1:
                    print "query not editable, because table %r is not found in db %r" % (
                        table,
                        self.current_host.current_db,
                    )
                    return None, None, None, None, None
                new_tables = self.current_host.current_db.refresh()
                continue
        # does this field really exist in this table?
        c = 0
        possible_primary = possible_unique = ""
        unique = primary = ""
        pri_okay = uni_okay = 0

        for i in new_tables:
            self.current_host.current_db.tables[i].refresh(False)

        if not th.fields and not table in new_tables:
            th.refresh(False)

        row_iter = None
        if path:
            row_iter = self.model.get_iter(path)

        # get unique where_clause
        self.kv_list = []
        self.last_th = th
        field_pos = 0
        for db_field_object in th.fields:
            if (pri_okay >= 0 and db_field_object.row["Key"] == "PRI") or (
                th.host.__class__.__name__ == "sqlite_host" and db_field_object.name.endswith("_id")
            ):
                if possible_primary:
                    possible_primary += ", "
                possible_primary += db_field_object.name
                if wildcard:
                    c = field_pos
                else:
                    c = None
                    try:
                        c = fields.index(db_field_object.name)
                    except:
                        pass
                if not c is None:
                    pri_okay = 1
                    if path:
                        value = self.model.get_value(row_iter, c)
                        if primary:
                            primary += " and "
                        primary += "`%s`='%s'" % (db_field_object.name, value)
                        self.kv_list.append((db_field_object.name, value))
            if uni_okay >= 0 and db_field_object.row["Key"] == "UNI":
                if possible_unique:
                    possible_unique += ", "
                possible_unique += db_field_object.name
                if wildcard:
                    c = field_pos
                else:
                    c = None
                    try:
                        c = fields.index(db_field_object.name)
                    except:
                        pass
                if not c is None:
                    uni_okay = 1
                    if path:
                        value = self.model.get_value(row_iter, c)
                        if unique:
                            unique += " and "
                        unique += "`%s`='%s'" % (db_field_object.name, value)
                        self.kv_list.append((db_field_object.name, value))
            field_pos += 1

        if uni_okay < 1 and pri_okay < 1:
            possible_key = "(i can't see any key-fields in this table...)"
            if possible_primary:
                possible_key = "e.g.'%s' would be useful!" % possible_primary
            elif possible_unique:
                possible_key = "e.g.'%s' would be useful!" % possible_unique
            print "no edit-key found. try to name a key-field in your select-clause. (%r)" % possible_key
            return table, None, None, None, None

        value = ""
        db_field_object = None
        if path:
            where = primary
            if not where:
                where = unique
            if not where:
                where = None
            if not col_num is None:
                value = self.model.get_value(row_iter, col_num)
                if wildcard:
                    db_field_object = th.field_order[col_num]
                else:
                    db_field_object = fields[col_num]
        else:
            where = possible_primary + possible_unique

        # get current edited field and value by col_num
        if return_fields:
            return table, where, db_field_object, value, row_iter, fields
        return table, where, db_field_object, value, row_iter

    def on_query_change_data(self, cellrenderer, path, new_value, col_num, force_update=False):
        row_iter = self.model.get_iter(path)
        if (
            self.append_iter
            and self.model.iter_is_valid(self.append_iter)
            and self.model.get_path(self.append_iter) == self.model.get_path(row_iter)
        ):
            self.filled_fields[self.treeview.get_column(col_num).get_title().replace("__", "_")] = new_value
            self.model.set_value(row_iter, col_num, new_value)
            return

        table, where, field, value, row_iter = self.get_unique_where(self.last_source, path, col_num)
        if force_update is False and new_value == value:
            return
        if self.current_host.__class__.__name__ == "sqlite_host":
            limit = ""
        else:
            limit = " limit 1"
        update_query = u"update %s set %s='%s' where %s%s" % (
            self.current_host.escape_table(table),
            self.current_host.escape_field(field),
            self.current_host.escape(new_value),
            where,
            limit,
        )
        if self.current_host.query(update_query, encoding=self.encoding):
            print "set new value: %r" % new_value
            self.model.set_value(row_iter, col_num, new_value)
            return True
        return False

    def on_sort_timer(self):
        if not self.sort_timer_running:
            return False
        if self.sort_timer_execute > time.time():
            return True
        self.sort_timer_running = False
        self.on_execute_query_clicked()
        return False

    def get_ui(self):
        return self.ui