diff options
author | Peter Harvey <peter.a.harvey@gmail.com> | 2006-01-29 06:14:02 +0800 |
---|---|---|
committer | Peter Anthony Harvey <paharvey@src.gnome.org> | 2006-01-29 06:14:02 +0800 |
commit | 811f68e7ed17fd4d4fcd620c3b9d1a543b376a9a (patch) | |
tree | c1b331413964754380f4ca45a6755c7a3daf8a85 /src/bookmarks/ephy-topics-entry.c | |
parent | 37a127559b9b67bd7b163177ced72539512c319c (diff) | |
download | gsoc2013-epiphany-811f68e7ed17fd4d4fcd620c3b9d1a543b376a9a.tar.gz gsoc2013-epiphany-811f68e7ed17fd4d4fcd620c3b9d1a543b376a9a.tar.zst gsoc2013-epiphany-811f68e7ed17fd4d4fcd620c3b9d1a543b376a9a.zip |
src/bookmarks/ephy-bookmark-properties.c src/bookmarks/ephy-topics-entry.c
2006-01-29 Peter Harvey <peter.a.harvey@gmail.com>
* src/bookmarks/ephy-bookmark-properties.c
* src/bookmarks/ephy-topics-entry.c
* src/bookmarks/ephy-topics-entry.h
* src/bookmarks/Makefile.am
* po/POTFILES.in
Ongoing Saga Of The Bookmark Properties Dialog.
Dialog is now much more compact, using a text entry by
default and offering the palette when desired.
* src/bookmarks/ephy-topics-palette.c
Simplified code and made more usable.
Removed the header from the last patch as well.
* src/bookmarks/ephy-bookmarks-ui.c
'Add bookmark' dialogs were not correctly removed from the
hashtable.
Diffstat (limited to 'src/bookmarks/ephy-topics-entry.c')
-rw-r--r-- | src/bookmarks/ephy-topics-entry.c | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/src/bookmarks/ephy-topics-entry.c b/src/bookmarks/ephy-topics-entry.c new file mode 100644 index 000000000..8c3af0007 --- /dev/null +++ b/src/bookmarks/ephy-topics-entry.c @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2002-2004 Marco Pesenti Gritti <mpeseng@tin.it> + * Copyright (C) 2005, 2006 Peter Harvey <pah06@uow.edu.au> + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ephy-topics-entry.h" +#include "ephy-nodes-cover.h" +#include "ephy-node-common.h" +#include "ephy-bookmarks.h" +#include "ephy-debug.h" + +#include <glib/gi18n.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtkentrycompletion.h> +#include <string.h> + +static void ephy_topics_entry_class_init (EphyTopicsEntryClass *klass); +static void ephy_topics_entry_init (EphyTopicsEntry *editor); + +#define EPHY_TOPICS_ENTRY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_TOPICS_ENTRY, EphyTopicsEntryPrivate)) + +struct _EphyTopicsEntryPrivate +{ + EphyBookmarks *bookmarks; + EphyNode *bookmark; + GtkListStore *store; + GtkEntryCompletion *completion; + gboolean update_keywords; + char *action; +}; + +enum +{ + PROP_0, + PROP_BOOKMARKS, + PROP_BOOKMARK +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_topics_entry_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + static const GTypeInfo our_info = + { + sizeof (EphyTopicsEntryClass), + NULL, + NULL, + (GClassInitFunc) ephy_topics_entry_class_init, + NULL, + NULL, + sizeof (EphyTopicsEntry), + 0, + (GInstanceInitFunc) ephy_topics_entry_init + }; + + type = g_type_register_static (GTK_TYPE_ENTRY, + "EphyTopicsEntry", + &our_info, 0); + } + + return type; +} + +static void +update_widget (EphyTopicsEntry *entry) +{ + EphyNode *node; + GPtrArray *children, *topics; + GtkTreeIter iter; + gint i, priority; + const char *title; + char *tmp1, *tmp2; + gboolean update_text; + + entry->priv->update_keywords = FALSE; + + update_text = !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry)); + gtk_entry_set_completion (GTK_ENTRY (entry), NULL); + gtk_list_store_clear (entry->priv->store); + if (update_text) gtk_entry_set_text (GTK_ENTRY (entry), ""); + + node = ephy_bookmarks_get_keywords (entry->priv->bookmarks); + children = ephy_node_get_children (node); + topics = g_ptr_array_sized_new (children->len); + + for (i = 0; i < children->len; i++) + { + node = g_ptr_array_index (children, i); + + priority = ephy_node_get_property_int (node, EPHY_NODE_KEYWORD_PROP_PRIORITY); + if (priority != EPHY_NODE_NORMAL_PRIORITY) + continue; + + g_ptr_array_add (topics, node); + } + + g_ptr_array_sort (topics, ephy_bookmarks_compare_topic_pointers); + + for (i = 0; i < topics->len; i++) + { + node = g_ptr_array_index (topics, i); + title = ephy_node_get_property_string (node, EPHY_NODE_KEYWORD_PROP_NAME); + + if (ephy_node_has_child (node, entry->priv->bookmark)) + { + if (update_text) + { + gtk_entry_append_text (GTK_ENTRY (entry), title); + gtk_entry_append_text (GTK_ENTRY (entry), "; "); + } + } + else + { + tmp1 = g_utf8_casefold (title, -1); + tmp2 = g_utf8_normalize (tmp1, -1, G_NORMALIZE_DEFAULT); + gtk_list_store_append (entry->priv->store, &iter); + gtk_list_store_set (entry->priv->store, &iter, 0, title, 1, tmp2, -1); + g_free (tmp2); + g_free (tmp1); + } + } + + g_ptr_array_free (topics, TRUE); + + gtk_entry_set_completion (GTK_ENTRY (entry), entry->priv->completion); + if (update_text) gtk_editable_set_position (GTK_EDITABLE (entry), -1); + + entry->priv->update_keywords = TRUE; +} + +static void +update_action (EphyTopicsEntry *entry) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + const char *text = gtk_entry_get_text (GTK_ENTRY (entry)); + char *key; + gint start, end; + + if(entry->priv->action) + { + gtk_entry_completion_delete_action (entry->priv->completion, 0); + g_free (entry->priv->action); + entry->priv->action = 0; + } + + /* Find the start and end locations */ + start = gtk_editable_get_position (editable); + while (start > 0 && text[start-1] != ';') + { + start--; + } + if(start > 0 && text[start-1] == ';' && text[start] == ' ') + { + start++; + } + end = start; + while (text[end] && text[end] != ';') + { + end++; + } + + /* If no text to work with, exit */ + key = g_strndup (text+start, end-start); + g_strstrip (key); + if (*key != 0 && ephy_bookmarks_find_keyword (entry->priv->bookmarks, key, FALSE) == NULL) + { + entry->priv->action = key; + key = g_strdup_printf (_("Create topic ā%sā"), key); + gtk_entry_completion_insert_action_text (entry->priv->completion, 0, key); + } + + g_free (key); +} + +static void +update_keywords (EphyTopicsEntry *entry) +{ + EphyNode *node; + GPtrArray *children; + const char *text; + char **split; + char *title, *tmp; + gint i, j, priority; + + if(!entry->priv->update_keywords) return; + + /* Get the list of strings input by the user */ + text = gtk_entry_get_text (GTK_ENTRY (entry)); + split = g_strsplit (text, ";", 0); + for (i=0; split[i]; i++) + { + g_strstrip (split[i]); + + tmp = g_utf8_casefold (split[i], -1); + g_free (split[i]); + + split[i] = g_utf8_normalize (tmp, -1, G_NORMALIZE_DEFAULT); + g_free (tmp); + } + + /* Test each keyword and set/unset as appropriate */ + node = ephy_bookmarks_get_keywords (entry->priv->bookmarks); + children = ephy_node_get_children (node); + for (i = 0; i < children->len; i++) + { + node = g_ptr_array_index (children, i); + + priority = ephy_node_get_property_int (node, EPHY_NODE_KEYWORD_PROP_PRIORITY); + if (priority != EPHY_NODE_NORMAL_PRIORITY) + continue; + + text = ephy_node_get_property_string (node, EPHY_NODE_KEYWORD_PROP_NAME); + tmp = g_utf8_casefold (text, -1); + title = g_utf8_normalize (tmp, -1, G_NORMALIZE_DEFAULT); + g_free (tmp); + + for (j=0; split[j]; j++) + if (strcmp (title, split[j]) == 0) + break; + + if (split[j]) + { + split[j][0] = 0; + ephy_bookmarks_set_keyword (entry->priv->bookmarks, node, + entry->priv->bookmark); + } + else + { + ephy_bookmarks_unset_keyword (entry->priv->bookmarks, node, + entry->priv->bookmark); + } + + g_free (title); + } + + g_strfreev (split); + + update_action (entry); +} + +static void +insert_text (EphyTopicsEntry *entry, + const char *title) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + const char *text = gtk_entry_get_text (GTK_ENTRY (entry)); + char *key; + gint start, end; + + /* Find the start and end locations */ + start = gtk_editable_get_position (editable); + while (start > 0 && text[start-1] != ';') + { + start--; + } + if(start > 0 && text[start-1] == ';' && text[start] == ' ') + { + start++; + } + end = start; + while (text[end] && text[end] != ';') + { + end++; + } + end = end; + if (text[end] == ';') + { + end++; + if (text[end] == ' ') + { + end++; + } + } + + /* If we were provided with nothing, then we're meant to find a topic + * or create one from whatever has been entered */ + if (title == NULL) + { + /* If no text to work with, exit */ + key = g_strndup (text+start, end-start); + g_strstrip (key); + if (*key == 0) + { + g_free (key); + return; + } + + } + + /* Replace the text in the current position with the title */ + gtk_editable_delete_text (editable, start, end); + gtk_editable_insert_text (editable, title, strlen(title), &start); + gtk_editable_insert_text (editable, "; ", 2, &start); + gtk_editable_set_position (editable, start); + update_widget(entry); +} + +static void +action_cb (GtkEntryCompletion *completion, + gint index, + gpointer user_data) +{ + EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (gtk_entry_completion_get_entry (completion)); + char *action = g_strdup(entry->priv->action); + + if (ephy_bookmarks_find_keyword (entry->priv->bookmarks, action, FALSE) == NULL) + { + ephy_bookmarks_add_keyword (entry->priv->bookmarks, action); + } + + insert_text (entry, action); + g_free (action); +} + +static gboolean +match_selected_cb (GtkEntryCompletion *completion, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (gtk_entry_completion_get_entry (completion)); + char *title; + + gtk_tree_model_get (model, iter, 0, &title, -1); + insert_text (entry, title); + g_free (title); + + return TRUE; +} + +static void +tree_changed_cb (EphyBookmarks *bookmarks, + EphyTopicsEntry *entry) +{ + update_widget(entry); +} + +static gboolean +focus_out_cb (GtkEditable *editable, + GdkEventFocus *event, + gpointer user_data) +{ + update_widget (EPHY_TOPICS_ENTRY (editable)); + return FALSE; +} + +static gboolean +match_func (GtkEntryCompletion *completion, + const gchar *key, + GtkTreeIter *iter, + gpointer user_data) +{ + gboolean result; + const char *real_key; + char *text; + + real_key = g_strrstr (key, ";"); + if (real_key) real_key++; + else real_key = key; + while (*real_key == ' ') real_key++; + + gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter, 1, &text, -1); + if (text == NULL) return FALSE; + result = g_str_has_prefix (text, real_key); + g_free (text); + + return result; +} + +static void +ephy_topics_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (object); + + switch (prop_id) + { + case PROP_BOOKMARKS: + entry->priv->bookmarks = g_value_get_object (value); + g_signal_connect_object (entry->priv->bookmarks, "tree-changed", + G_CALLBACK (tree_changed_cb), entry, + G_CONNECT_AFTER); + break; + case PROP_BOOKMARK: + entry->priv->bookmark = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +ephy_topics_entry_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GObject *object; + EphyTopicsEntry *entry; + EphyTopicsEntryPrivate *priv; + + object = parent_class->constructor (type, n_construct_properties, + construct_params); + entry = EPHY_TOPICS_ENTRY (object); + priv = EPHY_TOPICS_ENTRY_GET_PRIVATE (object); + + priv->store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + priv->completion = gtk_entry_completion_new (); + priv->update_keywords = TRUE; + + gtk_entry_completion_set_model (priv->completion, GTK_TREE_MODEL (priv->store)); + gtk_entry_completion_set_text_column (priv->completion, 0); + gtk_entry_completion_set_popup_completion (priv->completion, TRUE); + gtk_entry_completion_set_popup_single_match (priv->completion, TRUE); + + gtk_entry_completion_set_match_func (priv->completion, match_func, NULL, NULL); + + g_signal_connect (priv->completion, "match-selected", + G_CALLBACK (match_selected_cb), NULL); + g_signal_connect (object, "focus-out-event", + G_CALLBACK (focus_out_cb), NULL); + g_signal_connect (object, "changed", + G_CALLBACK (update_keywords), NULL); + g_signal_connect (G_OBJECT (priv->completion), "action-activated", + G_CALLBACK (action_cb), NULL); + + update_widget (entry); + + return object; +} + +static void +ephy_topics_entry_init (EphyTopicsEntry *entry) +{ + entry->priv = EPHY_TOPICS_ENTRY_GET_PRIVATE (entry); + +} + +static void +ephy_topics_entry_finalize (GObject *object) +{ + EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (object); + + g_free (entry->priv->action); + + parent_class->finalize (object); +} + +GtkWidget * +ephy_topics_entry_new (EphyBookmarks *bookmarks, + EphyNode *bookmark) +{ + EphyTopicsEntry *entry; + + g_assert (bookmarks != NULL); + + entry = EPHY_TOPICS_ENTRY (g_object_new + (EPHY_TYPE_TOPICS_ENTRY, + "bookmarks", bookmarks, + "bookmark", bookmark, + NULL)); + + return GTK_WIDGET (entry); +} + +static void +ephy_topics_entry_class_init (EphyTopicsEntryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->set_property = ephy_topics_entry_set_property; + object_class->constructor = ephy_topics_entry_constructor; + object_class->finalize = ephy_topics_entry_finalize; + + g_object_class_install_property (object_class, + PROP_BOOKMARKS, + g_param_spec_object ("bookmarks", + "Bookmarks set", + "Bookmarks set", + EPHY_TYPE_BOOKMARKS, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property (object_class, + PROP_BOOKMARK, + g_param_spec_pointer ("bookmark", + "Bookmark", + "Bookmark", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB)); + + g_type_class_add_private (object_class, sizeof(EphyTopicsEntryPrivate)); +} |