[frogr] Added new widget to support autocompletion in a centralized way.
- From: Mario Sanchez Prada <msanchez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [frogr] Added new widget to support autocompletion in a centralized way.
- Date: Mon, 22 Aug 2011 12:22:14 +0000 (UTC)
commit 6d177030ebb12b4f51f39af48ce3622f191a55a8
Author: Mario Sanchez Prada <msanchez igalia com>
Date: Mon Aug 22 14:19:33 2011 +0200
Added new widget to support autocompletion in a centralized way.
This new widget (FrogrLiveEntry) will primarily be used for tag
autocompletion both in the 'edit details' and 'add tags' dialogs, as
it's just a subclass of GtkEntry containing the code so far duplicated
both in the FrogrDetailsDialog and FrogrAddTagsDialog classes.
src/Makefile.am | 2 +
src/frogr-live-entry.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++
src/frogr-live-entry.h | 56 +++++++++++
3 files changed, 317 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 42589ed..2cfc7b0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,6 +48,8 @@ frogr_SOURCES = \
frogr-account.h \
frogr-add-tags-dialog.c \
frogr-add-tags-dialog.h \
+ frogr-live-entry.c \
+ frogr-live-entry.h \
frogr-add-to-set-dialog.c \
frogr-add-to-set-dialog.h \
frogr-add-to-group-dialog.c \
diff --git a/src/frogr-live-entry.c b/src/frogr-live-entry.c
new file mode 100644
index 0000000..6a77fd2
--- /dev/null
+++ b/src/frogr-live-entry.c
@@ -0,0 +1,259 @@
+/*
+ * frogr-live-entry.c -- Frogr 'live' entry (autocompletion enabled)
+ *
+ * Copyright (C) 2011 Mario Sanchez Prada
+ * Authors: Mario Sanchez Prada <msanchez igalia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 3 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "frogr-live-entry.h"
+
+#include "frogr-global-defs.h"
+#include "frogr-picture.h"
+
+#include <config.h>
+#include <glib/gi18n.h>
+
+#define FROGR_LIVE_ENTRY_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+ FROGR_TYPE_LIVE_ENTRY, \
+ FrogrLiveEntryPrivate))
+
+G_DEFINE_TYPE (FrogrLiveEntry, frogr_live_entry, GTK_TYPE_ENTRY)
+
+typedef struct _FrogrLiveEntryPrivate {
+ GtkEntryCompletion *entry_completion;
+ GtkTreeModel *treemodel;
+ gboolean auto_completion;
+} FrogrLiveEntryPrivate;
+
+
+/* Tree view columns */
+enum {
+ TEXT_COL,
+ N_COLS
+};
+
+
+/* Prototypes */
+
+static void _populate_treemodel_with_data (GtkTreeModel *treemodel, GSList *tags);
+
+static gboolean _tag_list_completion_func (GtkEntryCompletion *completion, const gchar *key,
+ GtkTreeIter *iter, gpointer data);
+
+static gboolean _completion_match_selected_cb (GtkEntryCompletion *widget, GtkTreeModel *model,
+ GtkTreeIter *iter, gpointer data);
+
+/* Private API */
+
+static void
+_populate_treemodel_with_data (GtkTreeModel *treemodel, GSList *tags)
+{
+ if (treemodel && tags)
+ {
+ GSList *item = NULL;
+ gchar *tag = NULL;
+ GtkTreeIter iter;
+
+ /* Initialize the list store */
+ for (item = tags; item; item = g_slist_next (item))
+ {
+ tag = (gchar *) item->data;
+ gtk_list_store_append (GTK_LIST_STORE (treemodel), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (treemodel), &iter,
+ 0, tag, -1);
+ }
+ }
+ else if (treemodel)
+ {
+ /* Clear the list store */
+ gtk_list_store_clear (GTK_LIST_STORE (treemodel));
+ }
+}
+
+static gboolean
+_tag_list_completion_func (GtkEntryCompletion *completion, const gchar *key,
+ GtkTreeIter *iter, gpointer data)
+{
+ FrogrLiveEntry *self = NULL;
+ FrogrLiveEntryPrivate *priv = NULL;
+ gchar *stripped_entry_text = NULL;
+ gchar *basetext = NULL;
+ gchar *tag = NULL;
+ gchar *lc_basetext = NULL;
+ gchar *lc_tag = NULL;
+ gint cursor_pos = 0;
+ gboolean matches = FALSE;
+
+ self = FROGR_LIVE_ENTRY (data);
+ priv = FROGR_LIVE_ENTRY_GET_PRIVATE (self);
+ gtk_tree_model_get (priv->treemodel, iter, TEXT_COL, &tag, -1);
+
+ /* Do nothing if not a valid tag */
+ if (!tag)
+ return FALSE;
+
+ /* Do nothing if the cursor is not in the last position */
+ cursor_pos = gtk_editable_get_position (GTK_EDITABLE (self));
+ if (cursor_pos < gtk_entry_get_text_length (GTK_ENTRY (self)))
+ return FALSE;
+
+ /* Look for the last token in 'key' */
+ stripped_entry_text = gtk_editable_get_chars (GTK_EDITABLE (self), 0, cursor_pos);
+ stripped_entry_text = g_strstrip (stripped_entry_text);
+ basetext = g_strrstr (stripped_entry_text, " ");
+ if (basetext)
+ basetext++;
+ else
+ basetext = stripped_entry_text;
+
+ /* Downcase everything and compare */
+ lc_basetext = g_utf8_strdown (basetext, -1);
+ lc_tag = g_utf8_strdown (tag, -1);
+ if (g_str_has_prefix (lc_tag, lc_basetext))
+ matches = TRUE;
+
+ g_free (stripped_entry_text);
+ g_free (tag);
+ g_free (lc_basetext);
+ g_free (lc_tag);
+
+ return matches;
+}
+
+static gboolean
+_completion_match_selected_cb (GtkEntryCompletion *widget, GtkTreeModel *model,
+ GtkTreeIter *iter, gpointer data)
+{
+ FrogrLiveEntry *self = NULL;
+ gchar *tag = NULL;
+ const gchar *entry_text = NULL;
+ const gchar *matching_text = NULL;
+ gchar *base_text = NULL;
+ gchar *new_text = NULL;
+ glong entry_text_len = 0;
+ glong matching_text_len = 0;
+
+ self = FROGR_LIVE_ENTRY (data);
+ gtk_tree_model_get (model, iter, TEXT_COL, &tag, -1);
+
+ entry_text = gtk_entry_get_text (GTK_ENTRY (self));
+ matching_text = g_strrstr (entry_text, " ");
+ if (matching_text)
+ matching_text++;
+ else
+ matching_text = entry_text;
+
+ entry_text_len = gtk_entry_get_text_length (GTK_ENTRY (self));
+ matching_text_len = g_utf8_strlen (matching_text, -1);
+
+ base_text = gtk_editable_get_chars (GTK_EDITABLE (self), 0, entry_text_len - matching_text_len);
+ new_text = g_strdup_printf ("%s%s ", base_text, tag);
+
+ gtk_entry_set_text (GTK_ENTRY (self), new_text);
+ gtk_editable_set_position (GTK_EDITABLE (self), -1);
+
+ g_free (tag);
+ g_free (base_text);
+ g_free (new_text);
+
+ return TRUE;
+}
+
+static void
+_frogr_live_entry_dispose (GObject *object)
+{
+ FrogrLiveEntryPrivate *priv = FROGR_LIVE_ENTRY_GET_PRIVATE (object);
+
+ if (priv->entry_completion)
+ {
+ g_object_unref (priv->entry_completion);
+ priv->entry_completion = NULL;
+ }
+
+ if (priv->treemodel)
+ {
+ g_object_unref (priv->treemodel);
+ priv->treemodel = NULL;
+ }
+
+ G_OBJECT_CLASS(frogr_live_entry_parent_class)->dispose (object);
+}
+
+static void
+frogr_live_entry_class_init (FrogrLiveEntryClass *klass)
+{
+ GObjectClass *obj_class = (GObjectClass *)klass;
+
+ /* GObject signals */
+ obj_class->dispose = _frogr_live_entry_dispose;
+
+ g_type_class_add_private (obj_class, sizeof (FrogrLiveEntryPrivate));
+}
+
+static void
+frogr_live_entry_init (FrogrLiveEntry *self)
+{
+ FrogrLiveEntryPrivate *priv = FROGR_LIVE_ENTRY_GET_PRIVATE (self);
+
+ priv->entry_completion = NULL;
+ priv->treemodel = NULL;
+ priv->auto_completion = FALSE;
+}
+
+/* Public API */
+
+GtkWidget *
+frogr_live_entry_new (void)
+{
+ return GTK_WIDGET (g_object_new (FROGR_TYPE_LIVE_ENTRY, NULL));
+}
+
+void
+frogr_live_entry_set_auto_completion (FrogrLiveEntry *self, GSList *data)
+{
+ FrogrLiveEntryPrivate *priv = NULL;
+
+ priv = FROGR_LIVE_ENTRY_GET_PRIVATE (self);
+ priv->auto_completion = data ? TRUE : FALSE;
+
+ /* Initialize the auto-completion stuff if it's the first time */
+ if (priv->auto_completion && priv->entry_completion == NULL)
+ {
+ GtkTreeModel *model = NULL;
+
+ model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
+ priv->treemodel = model;
+
+ priv->entry_completion = gtk_entry_completion_new ();
+ gtk_entry_completion_set_text_column (GTK_ENTRY_COMPLETION (priv->entry_completion), TEXT_COL);
+ gtk_entry_completion_set_inline_completion (GTK_ENTRY_COMPLETION (priv->entry_completion), TRUE);
+ gtk_entry_completion_set_match_func (GTK_ENTRY_COMPLETION (priv->entry_completion),
+ _tag_list_completion_func,
+ self, NULL);
+
+ gtk_entry_completion_set_model (GTK_ENTRY_COMPLETION (priv->entry_completion), model);
+
+ gtk_entry_set_completion (GTK_ENTRY (self), priv->entry_completion);
+
+ g_signal_connect (G_OBJECT (priv->entry_completion), "match-selected",
+ G_CALLBACK (_completion_match_selected_cb), self);
+ }
+
+ /* Populate the tree model with the data (or 'no data) passed */
+ if (priv->treemodel)
+ _populate_treemodel_with_data (priv->treemodel, data);
+}
diff --git a/src/frogr-live-entry.h b/src/frogr-live-entry.h
new file mode 100644
index 0000000..190dbd7
--- /dev/null
+++ b/src/frogr-live-entry.h
@@ -0,0 +1,56 @@
+/*
+ * frogr-live-entry.h -- Frogr 'live' entry (autocompletion enabled)
+ *
+ * Copyright (C) 2011 Mario Sanchez Prada
+ * Authors: Mario Sanchez Prada <msanchez igalia com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 3 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef FROGR_LIVE_ENTRY_H
+#define FROGR_LIVE_ENTRY_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define FROGR_TYPE_LIVE_ENTRY (frogr_live_entry_get_type())
+#define FROGR_LIVE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, FROGR_TYPE_LIVE_ENTRY, FrogrLiveEntry))
+#define FROGR_LIVE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, FROGR_TYPE_LIVE_ENTRY, FrogrLiveEntryClass))
+#define FROGR_IS_LIVE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, FROGR_TYPE_LIVE_ENTRY))
+#define FROGR_IS_LIVE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FROGR_TYPE_LIVE_ENTRY))
+#define FROGR_LIVE_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FROGR_TYPE_LIVE_ENTRY, FrogrLiveEntryClass))
+
+typedef struct _FrogrLiveEntry FrogrLiveEntry;
+typedef struct _FrogrLiveEntryClass FrogrLiveEntryClass;
+
+struct _FrogrLiveEntryClass
+{
+ GtkEntryClass parent_class;
+};
+
+struct _FrogrLiveEntry
+{
+ GtkEntry parent;
+};
+
+GType frogr_live_entry_get_type (void) G_GNUC_CONST;
+
+GtkWidget *frogr_live_entry_new (void);
+
+void frogr_live_entry_set_auto_completion (FrogrLiveEntry *self, GSList *data);
+
+G_END_DECLS /* FROGR_LIVE_ENTRY_H */
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]