[yelp/yelp-3-0] [yelp-location-entry] Doing automatic completion on topics in entry



commit 8ab562c85d40b0a8a0b2cb142b97d77afcca4efb
Author: Shaun McCance <shaunm gnome org>
Date:   Thu Mar 25 17:20:51 2010 -0500

    [yelp-location-entry] Doing automatic completion on topics in entry
    
    The core functionality is hooked up in YelpLocationEntry, but this commit
    just uses the history GtkTreeModel. We need to get the page list out of
    documents and use that for completion instead.

 libyelp/Makefile.am           |   26 ++++++-
 libyelp/yelp-location-entry.c |  175 ++++++++++++++++++++++++++++++++++++++++-
 libyelp/yelp-location-entry.h |   20 +++--
 libyelp/yelp-marshal.list     |    1 +
 src/yelp-window.c             |   27 ++++++
 5 files changed, 238 insertions(+), 11 deletions(-)
---
diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am
index ac847c5..85d2a40 100644
--- a/libyelp/Makefile.am
+++ b/libyelp/Makefile.am
@@ -8,6 +8,7 @@ libyelp_la_SOURCES =				\
 	yelp-io-channel.c			\
 	yelp-location-entry.c			\
 	yelp-mallard-document.c			\
+	yelp-marshal.c				\
 	yelp-settings.c				\
 	yelp-simple-document.c			\
 	yelp-transform.c			\
@@ -40,7 +41,30 @@ libyelp_include_HEADERS =			\
 	$(libyelp_headers)			\
 	yelp-types.h
 
-BUILT_SOURCES = yelp-types.c yelp-types.h
+BUILT_SOURCES =			\
+	stamp-yelp-marshal.h	\
+	yelp-marshal.c		\
+	yelp-marshal.h		\
+	yelp-types.c		\
+	yelp-types.h
+
+EXTRA_DIST = yelp-marshal.list
+
+yelp-marshal.h: stamp-yelp-marshal.h
+	@true
+
+stamp-yelp-marshal.h: yelp-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=yelp_marshal $(srcdir)/yelp-marshal.list --header > xgen-ymh \
+	&& (cmp -s xgen-ymh yelp-marshal.h || cp xgen-ymh yelp-marshal.h) \
+	&& rm -f xgen-ymh xgen-ymh~ \
+	&& echo timestamp > $(@F)
+
+yelp-marshal.c: yelp-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=yelp_marshal $(srcdir)/yelp-marshal.list --body > xgen-ymc \
+	&& cp xgen-ymc yelp-marshal.c \
+	&& rm -f xgen-ymc xgen-ymc~
+
+yelp-marshal-main.c: yelp-marshal.c
 
 CLEANFILES = $(BUILT_SOURCES)
 
diff --git a/libyelp/yelp-location-entry.c b/libyelp/yelp-location-entry.c
index 52e6b3d..6b8f926 100644
--- a/libyelp/yelp-location-entry.c
+++ b/libyelp/yelp-location-entry.c
@@ -25,6 +25,7 @@
 #include <glib/gi18n.h>
 
 #include "yelp-location-entry.h"
+#include "yelp-marshal.h"
 #include "yelp-settings.h"
 
 /**
@@ -111,6 +112,22 @@ static void     cell_set_text_cell                  (GtkCellLayout     *layout,
                                                      GtkTreeIter       *iter,
                                                      YelpLocationEntry *entry);
 
+/* GtkEntryCompletion callbacks */
+static void     cell_set_completion_text_cell       (GtkCellLayout     *layout,
+                                                     GtkCellRenderer   *cell,
+                                                     GtkTreeModel      *model,
+                                                     GtkTreeIter       *iter,
+                                                     YelpLocationEntry *entry);
+static gboolean entry_match_func                    (GtkEntryCompletion *completion,
+                                                     const gchar        *key,
+                                                     GtkTreeIter        *iter,
+                                                     YelpLocationEntry  *entry);
+static gboolean entry_match_selected                (GtkEntryCompletion *completion,
+                                                     GtkTreeModel       *model,
+                                                     GtkTreeIter        *iter,
+                                                     YelpLocationEntry  *entry);
+
+
 typedef struct _YelpLocationEntryPrivate  YelpLocationEntryPrivate;
 struct _YelpLocationEntryPrivate
 {
@@ -126,10 +143,15 @@ struct _YelpLocationEntryPrivate
     gboolean   search_mode;
 
     GtkCellRenderer *icon_cell;
+
+    /* owned by entry, do not free */
+    GtkEntryCompletion *completion;
+    gint                completion_desc_column;
 };
 
 enum {
   LOCATION_SELECTED,
+  COMPLETION_SELECTED,
   SEARCH_ACTIVATED,
   LAST_SIGNAL
 };
@@ -168,7 +190,7 @@ yelp_location_entry_class_init (YelpLocationEntryClass *klass)
      * will not be emitted.
      **/
     location_entry_signals[LOCATION_SELECTED] =
-        g_signal_new ("location_selected",
+        g_signal_new ("location-selected",
                       G_OBJECT_CLASS_TYPE (klass),
                       G_SIGNAL_RUN_LAST,
                       0, NULL, NULL,
@@ -176,6 +198,24 @@ yelp_location_entry_class_init (YelpLocationEntryClass *klass)
                       G_TYPE_NONE, 0);
 
     /**
+     * YelpLocationEntry::completion-selected
+     * @widget: The #YelpLocationEntry for which the signal was emitted.
+     * @model: The #GtkTreeModel contianing the completion.
+     * @iter: A #GtkTreeIter positioned at the completion.
+     * @user_data: User data set when the handler was connected.
+     *
+     * This signal will be emitted whenever a user selects an entry in the
+     * completion drop-down while typing.
+     **/
+    location_entry_signals[COMPLETION_SELECTED] =
+        g_signal_new ("completion-selected",
+                      G_OBJECT_CLASS_TYPE (klass),
+                      G_SIGNAL_RUN_LAST,
+                      0, NULL, NULL,
+                      yelp_marshal_VOID__OBJECT_BOXED,
+                      G_TYPE_NONE, 2, GTK_TYPE_TREE_MODEL, GTK_TYPE_TREE_ITER);
+
+    /**
      * YelpLocationEntry::search-activated
      * @widget: The #YelpLocationEntry for which the signal was emitted.
      * @text: The search text.
@@ -261,7 +301,8 @@ yelp_location_entry_class_init (YelpLocationEntryClass *klass)
                               sizeof (YelpLocationEntryPrivate));
 }
 
-static void yelp_location_entry_init (YelpLocationEntry *entry)
+static void
+yelp_location_entry_init (YelpLocationEntry *entry)
 {
     YelpLocationEntryPrivate *priv = GET_PRIV (entry);
     GList *cells;
@@ -289,7 +330,7 @@ static void yelp_location_entry_init (YelpLocationEntry *entry)
     g_object_set (cells->data, "xpad", 4, NULL);
     gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
                                         GTK_CELL_RENDERER (cells->data),
-                                        cell_set_text_cell,
+                                        (GtkCellLayoutDataFunc) cell_set_text_cell,
                                         entry, NULL);
     g_list_free (cells);
 
@@ -404,6 +445,49 @@ location_entry_start_search (YelpLocationEntry *entry,
     gtk_widget_grab_focus (priv->text_entry);
 }
 
+void
+yelp_location_entry_set_completion_model (YelpLocationEntry *entry,
+                                          GtkTreeModel *model,
+                                          gint text_column,
+                                          gint desc_column,
+                                          gint icon_column)
+{
+    YelpLocationEntryPrivate *priv = GET_PRIV (entry);
+    GList *cells;
+    GtkCellRenderer *icon_cell;
+
+    priv->completion = gtk_entry_completion_new ();
+    priv->completion_desc_column = desc_column;
+    gtk_entry_completion_set_model (priv->completion, model);
+    gtk_entry_completion_set_text_column (priv->completion, text_column);
+    gtk_entry_completion_set_match_func (priv->completion,
+                                         (GtkEntryCompletionMatchFunc) entry_match_func,
+                                         entry, NULL);
+    g_signal_connect (priv->completion, "match-selected",
+                      G_CALLBACK (entry_match_selected), entry);
+
+    cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->completion));
+    g_object_set (cells->data, "xpad", 4, NULL);
+    gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->completion),
+                                        GTK_CELL_RENDERER (cells->data),
+                                        (GtkCellLayoutDataFunc) cell_set_completion_text_cell,
+                                        entry, NULL);
+    g_list_free (cells);
+
+    icon_cell = gtk_cell_renderer_pixbuf_new ();
+    g_object_set (priv->icon_cell, "yalign", 0.2, NULL);
+    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->completion), icon_cell, FALSE);
+    gtk_cell_layout_reorder (GTK_CELL_LAYOUT (priv->completion), icon_cell, 0);
+    gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (priv->completion),
+                                    icon_cell,
+                                    "icon-name",
+                                    icon_column,
+                                    NULL);
+
+    gtk_entry_set_completion (GTK_ENTRY (priv->text_entry),
+                              priv->completion);
+}
+
 static void
 location_entry_set_entry (YelpLocationEntry *entry, gboolean emit)
 {
@@ -684,6 +768,91 @@ cell_set_text_cell (GtkCellLayout     *layout,
     }
 }
 
+static void
+cell_set_completion_text_cell (GtkCellLayout     *layout,
+                               GtkCellRenderer   *cell,
+                               GtkTreeModel      *model,
+                               GtkTreeIter       *iter,
+                               YelpLocationEntry *entry)
+{
+    gint text_col;
+    gchar *title, *desc, *color, *text;
+    YelpLocationEntryPrivate *priv = GET_PRIV (entry);
+
+    g_object_get (priv->completion, "text-column", &text_col, NULL);
+    if (text_col >= 0) {
+        gtk_tree_model_get (model, iter,
+                            text_col, &title,
+                            priv->completion_desc_column, &desc,
+                            -1);
+        if (desc) {
+            color = yelp_settings_get_color (yelp_settings_get_default (),
+                                             YELP_SETTINGS_COLOR_TEXT_LIGHT);
+            text = g_markup_printf_escaped ("<span size='larger'>%s</span>\n<span color='%s'>%s</span>",
+                                            title, color, desc);
+            g_free (color);
+            g_free (desc);
+        }
+        else {
+            text = g_markup_printf_escaped ("<span size='larger'>%s</span>", title);
+        }
+
+        g_object_set (cell, "markup", text, NULL);
+        g_free (text);
+        g_free (title);
+    }
+}
+
+static gboolean
+entry_match_func (GtkEntryCompletion *completion,
+                  const gchar        *key,
+                  GtkTreeIter        *iter,
+                  YelpLocationEntry  *entry)
+{
+    gint text_col;
+    gchar *txt = NULL, *txtcase;
+    gboolean ret = FALSE;
+    GtkTreeModel *model = gtk_entry_completion_get_model (completion);
+
+    g_object_get (entry, "text-column", &text_col, NULL);
+    gtk_tree_model_get (model, iter, text_col, &txt, -1);
+    if (txt == NULL)
+        return FALSE;
+    txtcase = g_utf8_casefold (txt, -1);
+
+    if (strstr (txtcase, key))
+        ret = TRUE;
+
+    g_free (txtcase);
+    g_free (txt);
+    if (ret)
+        return ret;
+
+    g_object_get (entry, "desc-column", &text_col, NULL);
+    gtk_tree_model_get (model, iter, text_col, &txt, -1);
+    if (txt == NULL)
+        return FALSE;
+    txtcase = g_utf8_casefold (txt, -1);
+
+    if (strstr (txtcase, key))
+        ret = TRUE;
+
+    g_free (txtcase);
+    g_free (txt);
+
+    return ret;
+}
+
+static gboolean
+entry_match_selected (GtkEntryCompletion *completion,
+                      GtkTreeModel       *model,
+                      GtkTreeIter        *iter,
+                      YelpLocationEntry  *entry)
+{
+    g_signal_emit (entry, location_entry_signals[COMPLETION_SELECTED], 0, model, iter);
+    return TRUE;
+}
+
 /**
  * yelp_location_entry_new_with_model:
  * @model: A #GtkTreeModel.
diff --git a/libyelp/yelp-location-entry.h b/libyelp/yelp-location-entry.h
index 6d6e306..08db5c9 100644
--- a/libyelp/yelp-location-entry.h
+++ b/libyelp/yelp-location-entry.h
@@ -79,14 +79,20 @@ typedef enum {
     YELP_LOCATION_ENTRY_IS_SEARCH    = 1 << 3
 } YelpLocationEntryFlags;
 
-GType           yelp_location_entry_get_type        (void);
-GtkWidget*      yelp_location_entry_new_with_model  (GtkTreeModel *model,
-                                                     gint          text_column,
-                                                     gint          desc_column,
-                                                     gint          icon_column,
-                                                     gint          flags_column);
+GType           yelp_location_entry_get_type             (void);
+GtkWidget*      yelp_location_entry_new_with_model       (GtkTreeModel      *model,
+                                                          gint               text_column,
+                                                          gint               desc_column,
+                                                          gint               icon_column,
+                                                          gint               flags_column);
 
-void            yelp_location_entry_start_search    (YelpLocationEntry *entry);
+void            yelp_location_entry_set_completion_model (YelpLocationEntry *entry,
+                                                          GtkTreeModel      *model,
+                                                          gint               text_column,
+                                                          gint               desc_column,
+                                                          gint               icon_column);
+
+void            yelp_location_entry_start_search         (YelpLocationEntry  *entry);
 
 G_END_DECLS
 
diff --git a/libyelp/yelp-marshal.list b/libyelp/yelp-marshal.list
new file mode 100644
index 0000000..0467222
--- /dev/null
+++ b/libyelp/yelp-marshal.list
@@ -0,0 +1 @@
+VOID:OBJECT,BOXED
diff --git a/src/yelp-window.c b/src/yelp-window.c
index ca1dc7c..b6253bd 100644
--- a/src/yelp-window.c
+++ b/src/yelp-window.c
@@ -58,6 +58,10 @@ static void          window_font_adjustment       (GtkAction          *action,
 
 static void          entry_location_selected      (YelpLocationEntry  *entry,
                                                    YelpWindow         *window);
+static void          entry_completion_selected    (YelpLocationEntry  *entry,
+                                                   GtkTreeModel       *model,
+                                                   GtkTreeIter        *iter,
+                                                   YelpWindow         *window);
 
 static void          back_button_clicked          (GtkWidget          *button,
                                                    YelpWindow         *window);
@@ -231,6 +235,15 @@ yelp_window_init (YelpWindow *window)
                                             COL_DESC,
                                             COL_ICON,
                                             COL_FLAGS);
+
+    yelp_location_entry_set_completion_model (YELP_LOCATION_ENTRY (priv->entry),
+                                              GTK_TREE_MODEL (priv->history),
+                                              COL_TITLE,
+                                              COL_DESC,
+                                              COL_ICON);
+    g_signal_connect (priv->entry, "completion-selected",
+                      G_CALLBACK (entry_completion_selected), window);
+
     priv->entry_location_selected = g_signal_connect (priv->entry, "location-selected",
                                                       G_CALLBACK (entry_location_selected), window);
     priv->align_location = g_object_ref_sink (gtk_alignment_new (0.0, 0.5, 1.0, 0.0));
@@ -470,6 +483,20 @@ entry_location_selected (YelpLocationEntry  *entry,
 }
 
 static void
+entry_completion_selected (YelpLocationEntry  *entry,
+                           GtkTreeModel       *model,
+                           GtkTreeIter        *iter,
+                           YelpWindow         *window)
+{
+    gchar *uri;
+    YelpWindowPrivate *priv = GET_PRIV (window);
+    gtk_tree_model_get (model, iter, COL_URI, &uri, -1);
+    yelp_view_load (priv->view, uri);
+    g_free (uri);
+    gtk_widget_grab_focus (GTK_WIDGET (priv->view));
+}
+
+static void
 back_button_clicked (GtkWidget  *button,
                      YelpWindow *window)
 {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]