summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@gnome.org>2009-07-08 17:37:41 +0200
committerBenjamin Otte <otte@gnome.org>2009-07-08 17:37:41 +0200
commitf18f7da25030e022abab3bcb9b2a89edf3eeef3a (patch)
tree4a41704b2521e949deada9d6759346a81157d8dc
parent81ee91ce9622f8bf269fdb2b4e6b18cb617cfcbf (diff)
Add another test application to play with entry completion
-rw-r--r--.gitignore1
-rw-r--r--Makefile13
-rw-r--r--ephy-entry-completion.c313
3 files changed, 325 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index ab513c8..afc7c88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
*.o
+ephy-entry-completion
ephy-query-history
diff --git a/Makefile b/Makefile
index d874ea2..7cb512f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
APP = ephy-query-history
+APP2 = ephy-entry-completion
CC = gcc
CFLAGS = -g -DEPIPHANY_COMPILATION -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wold-style-definition -Wdeclaration-after-statement -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wformat-nonliteral -Wformat-security -Wswitch-enum -Wswitch-default -Winit-self -Wmissing-include-dirs -Wundef -Waggregate-return -Wmissing-format-attribute -Wnested-externs -Wunsafe-loop-optimizations -Wpacked -Winvalid-pch -Wlogical-op -Werror
@@ -6,13 +7,18 @@ PKG = gtk+-2.0 gthread-2.0 sqlite3
PKG_CFLAGS = `pkg-config --cflags $(PKG)`
PKG_LIBS = `pkg-config --libs $(PKG)`
-SRCS = \
+SRCS = \
ephy-history.c \
ephy-query-history.c
+SRCS2 = \
+ ephy-history.c \
+ ephy-entry-completion.c
+
OBJS = $(SRCS:.c=.o)
+OBJS2 = $(SRCS2:.c=.o)
-all: $(APP)
+all: $(APP) $(APP2)
.c.o:
$(CC) $(CFLAGS) $(PKG_CFLAGS) -c $< -o $@
@@ -20,6 +26,9 @@ all: $(APP)
$(APP): $(OBJS)
$(CC) $(OBJS) $(PKG_LIBS) -o$(APP)
+$(APP2): $(OBJS2)
+ $(CC) $(OBJS2) $(PKG_LIBS) -o$(APP2)
+
clean:
rm *.o $(APP)
diff --git a/ephy-entry-completion.c b/ephy-entry-completion.c
new file mode 100644
index 0000000..4c0c065
--- /dev/null
+++ b/ephy-entry-completion.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright © 2009 Benjamin Otte <otte@gnome.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+
+#include "ephy-history.h"
+
+enum {
+ LOCATION_COLUMN_ID,
+ LOCATION_COLUMN_FAVICON,
+ LOCATION_COLUMN_TEXT,
+ LOCATION_COLUMN_RELEVANCE,
+
+ LOCATION_N_COLUMNS
+};
+
+static gboolean
+return_true (GtkEntryCompletion *completion,
+ const char *key,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ return TRUE;
+}
+
+static GtkEntryCompletion *
+create_completion (void)
+{
+ GtkEntryCompletion *completion;
+ GtkCellRenderer *cell;
+
+ completion = gtk_entry_completion_new ();
+
+#if 0
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion),
+ cell, FALSE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion),
+ cell, "pixbuf", LOCATION_COLUMN_FAVICON);
+#endif
+
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "ellipsize-set", TRUE,
+ NULL);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion),
+ cell, TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion),
+ cell, "markup", LOCATION_COLUMN_TEXT);
+ gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (cell), 2);
+
+#if 0
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (completion),
+ cell, FALSE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion),
+ cell, extracell_data_func,
+ entry,
+ NULL);
+#endif
+
+ gtk_entry_completion_set_match_func (completion, return_true, NULL, NULL);
+
+ return completion;
+}
+
+typedef struct {
+ EphyHistory *history;
+ GtkListStore *store;
+ GCancellable *cancellable;
+ GtkTreeIter iter;
+ gboolean iter_valid;
+} ListStoreData;
+
+static void
+history_more_data_cb (GObject *history, GAsyncResult *res, gpointer _data)
+{
+ ListStoreData *data = _data;
+ GSList *rows;
+ GError *error = NULL;
+ static int columns[] = { LOCATION_COLUMN_ID, LOCATION_COLUMN_TEXT, LOCATION_COLUMN_RELEVANCE };
+
+ rows = ephy_history_select_finish (EPHY_HISTORY (history), res, &error);
+ if (rows == NULL)
+ {
+ if (error)
+ g_error_free (error);
+ else
+ {
+ g_object_unref (data->cancellable);
+ data->cancellable = NULL;
+ while (data->iter_valid)
+ data->iter_valid = gtk_list_store_remove (data->store,
+ &data->iter);
+ }
+ return;
+ }
+
+ if (data->iter_valid)
+ {
+ gint64 tree_id, row_id, tree_relevance, row_relevance;
+ GValueArray *row = rows->data;
+
+ /* try to match rows, so we just do updates */
+ gtk_tree_model_get (GTK_TREE_MODEL (data->store),
+ &data->iter,
+ LOCATION_COLUMN_ID, &tree_id,
+ LOCATION_COLUMN_RELEVANCE, &tree_relevance,
+ -1);
+ row_id = g_value_get_int64 (&row->values[0]);
+ row_relevance = g_value_get_int64 (&row->values[2]);
+ for (;;)
+ {
+ if (row_id == tree_id)
+ {
+ /*
+ * id of columns match - update values and advance iters
+ */
+ gtk_list_store_set_value (data->store, &data->iter,
+ LOCATION_COLUMN_TEXT, &row->values[1]);
+ data->iter_valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (data->store),
+ &data->iter);
+ rows = rows->next;
+ if (rows == NULL)
+ break;
+ row = rows->data;
+ row_id = g_value_get_int64 (&row->values[0]);
+ row_relevance = g_value_get_int64 (&row->values[2]);
+ }
+ else if (tree_relevance >= row_relevance)
+ {
+ /*
+ * The row in the tree has relevance that cannot be matched anymore.
+ * Remove it.
+ */
+ data->iter_valid = gtk_list_store_remove (data->store,
+ &data->iter);
+ }
+ else
+ {
+ /*
+ * Row has a higher relevance than current row in tree model.
+ * So insert the row before the row in the tree model.
+ */
+ GtkTreeIter insert;
+ gtk_list_store_insert_before (data->store,
+ &insert,
+ &data->iter);
+ gtk_list_store_set_valuesv (data->store,
+ &insert,
+ columns,
+ row->values,
+ G_N_ELEMENTS (columns));
+ rows = rows->next;
+ if (rows == NULL)
+ break;
+ row = rows->data;
+ row_id = g_value_get_int64 (&row->values[0]);
+ row_relevance = g_value_get_int64 (&row->values[2]);
+ /* no need to requery data that didn't change */
+ continue;
+ }
+ if (!data->iter_valid)
+ break;
+ gtk_tree_model_get (GTK_TREE_MODEL (data->store),
+ &data->iter,
+ LOCATION_COLUMN_ID, &tree_id,
+ LOCATION_COLUMN_RELEVANCE, &tree_relevance,
+ -1);
+ }
+ }
+
+ /* add rows at the end */
+ for (;rows; rows = rows->next)
+ {
+ GValueArray *row = rows->data;
+ GtkTreeIter insert;
+
+ gtk_list_store_insert_with_valuesv (data->store,
+ &insert,
+ G_MAXINT, /* end */
+ columns,
+ row->values,
+ G_N_ELEMENTS (columns));
+ }
+
+#if 0
+ {
+ GtkTreeIter iter;
+ gint64 relevance, id;
+ char *text;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (data->store), &iter))
+ do {
+ gtk_tree_model_get (GTK_TREE_MODEL (data->store), &iter,
+ LOCATION_COLUMN_RELEVANCE, &relevance,
+ LOCATION_COLUMN_ID, &id,
+ LOCATION_COLUMN_TEXT, &text,
+ -1);
+ g_print ("%5lld %5lld %s\n", relevance, id, text);
+ g_free (text);
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (data->store), &iter));
+ g_print ("\n");
+ }
+#endif
+}
+
+static void
+entry_changed_cb (GtkEntry *entry, ListStoreData *data)
+{
+ const char *text;
+ char *markup;
+
+ if (data->cancellable)
+ {
+ g_cancellable_cancel (data->cancellable);
+ g_object_unref (data->cancellable);
+ }
+
+ data->cancellable = g_cancellable_new ();
+ text = gtk_entry_get_text (entry);
+ markup = g_regex_escape_string (text, -1);
+
+ ephy_history_select_async (data->history,
+ 30,
+ 100,
+ history_more_data_cb,
+ data,
+ data->cancellable,
+ "select id, markup (%Q, url), n_visits from history where url match %Q order by n_visits desc limit 300",
+ markup, text);
+ data->iter_valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (data->store), &data->iter);
+ g_free (markup);
+}
+
+int
+main (int argc, char *argv[])
+{
+ static char *filename = NULL;
+ static GOptionEntry options[] = {
+ { "filename", 'f', 0, G_OPTION_ARG_FILENAME, &filename, "file to use as history instead of default", "FILENAME" },
+ { NULL }
+ };
+ GError *error = NULL;
+ GtkWidget *entry, *window;
+ GtkEntryCompletion *completion;
+ ListStoreData data;
+
+ g_thread_init (NULL);
+
+ gtk_init_with_args (&argc, &argv,
+ (char *) "Test location entry performance",
+ options,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_printerr ("Error parsing command line arguments: %s\n", error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ data.history = ephy_history_new (filename);
+ data.store = gtk_list_store_new (LOCATION_N_COLUMNS,
+ G_TYPE_INT64, /* LOCATION_COLUMN_ID */
+ GDK_TYPE_PIXBUF, /* LOCATION_COLUMN_FAVICON */
+ G_TYPE_STRING, /* LOCATION_COLUMN_TEXT */
+ G_TYPE_INT64); /* LOCATION_COLUMN_RELEVANCE */
+ data.cancellable = NULL;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ entry = gtk_entry_new ();
+ gtk_entry_set_width_chars (GTK_ENTRY (entry), 100);
+ gtk_container_add (GTK_CONTAINER (window), entry);
+ g_signal_connect (entry,
+ "changed",
+ G_CALLBACK (entry_changed_cb),
+ &data);
+
+ completion = create_completion ();
+ gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (data.store));
+ gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+ g_object_unref (completion);
+
+ gtk_widget_show_all (window);
+ gtk_main ();
+
+ return 0;
+}
+