diff options
author | Peter Harvey <peter.a.harvey@gmail.com> | 2006-01-29 18:24:56 +0800 |
---|---|---|
committer | Peter Anthony Harvey <paharvey@src.gnome.org> | 2006-01-29 18:24:56 +0800 |
commit | 30842d47d875fc89f84584aed9ef4894612aa037 (patch) | |
tree | 8894f89e7a4fcc10d19a16b0a2224bafc081821c /src | |
parent | b464665b4db8ad07b8f5d55b28a27fa01b5a6872 (diff) | |
download | gsoc2013-epiphany-30842d47d875fc89f84584aed9ef4894612aa037.tar gsoc2013-epiphany-30842d47d875fc89f84584aed9ef4894612aa037.tar.gz gsoc2013-epiphany-30842d47d875fc89f84584aed9ef4894612aa037.tar.bz2 gsoc2013-epiphany-30842d47d875fc89f84584aed9ef4894612aa037.tar.lz gsoc2013-epiphany-30842d47d875fc89f84584aed9ef4894612aa037.tar.xz gsoc2013-epiphany-30842d47d875fc89f84584aed9ef4894612aa037.tar.zst gsoc2013-epiphany-30842d47d875fc89f84584aed9ef4894612aa037.zip |
src/bookmarks/ephy-topics-entry.c src/bookmarks/ephy-topics-palette.c
2006-01-29 Peter Harvey <peter.a.harvey@gmail.com>
* src/bookmarks/ephy-topics-entry.c
* src/bookmarks/ephy-topics-palette.c
Make both topcs palette and entry even more robust.
Substantially improved behaviour of the topics entry.
Diffstat (limited to 'src')
-rw-r--r-- | src/bookmarks/ephy-topics-entry.c | 470 | ||||
-rw-r--r-- | src/bookmarks/ephy-topics-palette.c | 34 |
2 files changed, 317 insertions, 187 deletions
diff --git a/src/bookmarks/ephy-topics-entry.c b/src/bookmarks/ephy-topics-entry.c index 64145ca66..6153e53a7 100644 --- a/src/bookmarks/ephy-topics-entry.c +++ b/src/bookmarks/ephy-topics-entry.c @@ -41,8 +41,8 @@ struct _EphyTopicsEntryPrivate EphyNode *bookmark; GtkListStore *store; GtkEntryCompletion *completion; - gboolean update_keywords; - char *input; + gboolean lock; + char *create; char *key; }; @@ -53,6 +53,14 @@ enum PROP_BOOKMARK }; +enum +{ + COLUMN_NODE, + COLUMN_KEY, + COLUMN_TITLE, + COLUMNS +}; + static GObjectClass *parent_class = NULL; GType @@ -83,6 +91,76 @@ ephy_topics_entry_get_type (void) return type; } +static EphyNode * +find_topic (EphyTopicsEntry *entry, + const char *key) +{ + EphyNode *node = NULL; + GtkTreeModel *model; + GtkTreeIter iter; + GValue value = { 0, }; + gboolean valid; + + /* Loop through our table and set/unset topics appropriately */ + model = GTK_TREE_MODEL (entry->priv->store); + valid = gtk_tree_model_get_iter_first (model, &iter); + while (valid && node == NULL) + { + gtk_tree_model_get_value (model, &iter, COLUMN_KEY, &value); + if (strcmp(g_value_get_string (&value), key) == 0) + { + g_value_unset (&value); + gtk_tree_model_get_value (model, &iter, COLUMN_NODE, &value); + node = g_value_get_pointer (&value); + } + g_value_unset (&value); + valid = gtk_tree_model_iter_next (model, &iter); + } + + return node; +} + +static void +insert_text (EphyTopicsEntry *entry, + const char *title) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + const char *text = gtk_entry_get_text (GTK_ENTRY (entry)); + 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++; + } + } + + /* 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); +} + +/* Updates the text entry and the completion model to match the database */ static void update_widget (EphyTopicsEntry *entry) { @@ -97,7 +175,9 @@ update_widget (EphyTopicsEntry *entry) char *tmp1, *tmp2; gboolean update_text; - priv->update_keywords = FALSE; + /* Prevent any changes to the database */ + if(priv->lock) return; + priv->lock = TRUE; node = ephy_bookmarks_get_keywords (priv->bookmarks); children = ephy_node_get_children (node); @@ -107,7 +187,8 @@ update_widget (EphyTopicsEntry *entry) { node = g_ptr_array_index (children, i); - priority = ephy_node_get_property_int (node, EPHY_NODE_KEYWORD_PROP_PRIORITY); + priority = ephy_node_get_property_int + (node, EPHY_NODE_KEYWORD_PROP_PRIORITY); if (priority != EPHY_NODE_NORMAL_PRIORITY) continue; @@ -115,116 +196,65 @@ update_widget (EphyTopicsEntry *entry) } g_ptr_array_sort (topics, ephy_bookmarks_compare_topic_pointers); - gtk_list_store_clear (priv->store); + update_text = !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry)); - if (update_text) gtk_editable_delete_text (editable, 0, -1); - pos = 0; + if (update_text) + { + gtk_editable_delete_text (editable, 0, -1); + } - for (i = 0; i < topics->len; i++) + for (pos = 0, 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, priv->bookmark)) + if (update_text && ephy_node_has_child (node, priv->bookmark)) { - if (update_text) - { - gtk_editable_insert_text (editable, title, -1, &pos); - gtk_editable_insert_text (editable, "; ", -1, &pos); - } + gtk_editable_insert_text (editable, title, -1, &pos); + gtk_editable_insert_text (editable, "; ", -1, &pos); } - /* We just include all topics, else we get odd behaviour after you - * just finish entering a topic (it gets selected, so wouldn't show) */ tmp1 = g_utf8_casefold (title, -1); tmp2 = g_utf8_normalize (tmp1, -1, G_NORMALIZE_DEFAULT); gtk_list_store_append (priv->store, &iter); - gtk_list_store_set (priv->store, &iter, 0, title, 1, tmp2, -1); + gtk_list_store_set (priv->store, &iter, COLUMN_NODE, node, + COLUMN_TITLE, title, COLUMN_KEY, tmp2, -1); g_free (tmp2); g_free (tmp1); } - g_ptr_array_free (topics, TRUE); - if (update_text) gtk_editable_set_position (editable, -1); - - priv->update_keywords = TRUE; -} - -static void -update_input (EphyTopicsEntry *entry) -{ - GtkEditable *editable = GTK_EDITABLE (entry); - const char *text = gtk_entry_get_text (GTK_ENTRY (entry)); - char *input; - gint start, end; - - if (entry->priv->input) + if (update_text) { - gtk_entry_completion_delete_action (entry->priv->completion, 0); - g_free (entry->priv->input); - g_free (entry->priv->key); - entry->priv->input = 0; - entry->priv->key = 0; + gtk_editable_set_position (editable, -1); } - /* 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 */ - input = g_strndup (text+start, end-start); - g_strstrip (input); - if (*input != 0) - { - entry->priv->input = input; - - input = g_utf8_casefold (input, -1); - entry->priv->key = g_utf8_normalize (input, -1, G_NORMALIZE_DEFAULT); - g_free (input); - - if (ephy_bookmarks_find_keyword (entry->priv->bookmarks, entry->priv->input, FALSE) == NULL) - { - input = g_strdup_printf (_("Create topic ā%sā"), entry->priv->input); - gtk_entry_completion_insert_action_text (entry->priv->completion, 0, input); - g_free (input); - } - else - { - g_free (entry->priv->input); - entry->priv->input = 0; - } - } - else - { - g_free (input); - } + g_ptr_array_free (topics, TRUE); + + priv->lock = FALSE; } +/* Updates the bookmarks database to match what is in the text entry */ static void -update_keywords (EphyTopicsEntry *entry) +update_database (EphyTopicsEntry *entry) { + EphyTopicsEntryPrivate *priv = entry->priv; + EphyNode *node; - GPtrArray *children; const char *text; char **split; - char *title, *tmp; - gint i, j, priority; + char *tmp; + gint i; - if(!entry->priv->update_keywords) return; + GtkTreeModel *model; + GtkTreeIter iter; + GValue value = { 0, }; + gboolean valid; + + /* Prevent any changes to the text entry or completion model */ + if(priv->lock) return; + priv->lock = TRUE; /* Get the list of strings input by the user */ text = gtk_entry_get_text (GTK_ENTRY (entry)); @@ -240,53 +270,63 @@ update_keywords (EphyTopicsEntry *entry) 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++) + /* Loop through the completion model and set/unset topics appropriately */ + model = GTK_TREE_MODEL (priv->store); + valid = gtk_tree_model_get_iter_first (model, &iter); + while (valid) { - 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; + gtk_tree_model_get_value (model, &iter, COLUMN_NODE, &value); + node = g_value_get_pointer (&value); + g_value_unset (&value); - 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); + gtk_tree_model_get_value (model, &iter, COLUMN_KEY, &value); + text = g_value_get_string (&value); - for (j=0; split[j]; j++) - if (strcmp (title, split[j]) == 0) + for (i=0; split[i]; i++) + if (strcmp (text, split[i]) == 0) break; - if (split[j]) + if (split[i]) { - split[j][0] = 0; - ephy_bookmarks_set_keyword (entry->priv->bookmarks, node, - entry->priv->bookmark); + split[i][0] = 0; + ephy_bookmarks_set_keyword (priv->bookmarks, node, + priv->bookmark); } else { - ephy_bookmarks_unset_keyword (entry->priv->bookmarks, node, - entry->priv->bookmark); + ephy_bookmarks_unset_keyword (priv->bookmarks, node, + priv->bookmark); } - g_free (title); + g_value_unset (&value); + valid = gtk_tree_model_iter_next (model, &iter); } - - g_strfreev (split); + + priv->lock = FALSE; } +/* Updates the search key and topic creation action */ static void -insert_text (EphyTopicsEntry *entry, - const char *title) +update_key (EphyTopicsEntry *entry) { GtkEditable *editable = GTK_EDITABLE (entry); + EphyTopicsEntryPrivate *priv = entry->priv; + const char *text = gtk_entry_get_text (GTK_ENTRY (entry)); - char *key; + char *input; gint start, end; + /* If there was something we could create, then delete the action. */ + if (priv->create) + { + gtk_entry_completion_delete_action (priv->completion, 0); + } + + g_free (priv->create); + g_free (priv->key); + priv->create = 0; + priv->key = 0; + /* Find the start and end locations */ start = gtk_editable_get_position (editable); while (start > 0 && text[start-1] != ';') @@ -302,36 +342,94 @@ insert_text (EphyTopicsEntry *entry, { end++; } - end = end; - if (text[end] == ';') + + /* Set the priv->create and priv->key appropriately. */ + input = g_strndup (text+start, end-start); + g_strstrip (input); + if (*input != 0) { - end++; - if (text[end] == ' ') + priv->create = input; + + input = g_utf8_casefold (input, -1); + priv->key = g_utf8_normalize (input, -1, G_NORMALIZE_DEFAULT); + + if (find_topic (entry, priv->key) != NULL) { - end++; + g_free (priv->create); + priv->create = 0; } } + g_free (input); + + /* If there is something we can create, then setup the action. */ + if (priv->create) + { + input = g_strdup_printf (_("Create topic ā%sā"), priv->create); + gtk_entry_completion_insert_action_text (priv->completion, 0, input); + g_free (input); + } +} + +static gboolean +match_func (GtkEntryCompletion *completion, + const gchar *key, + GtkTreeIter *iter, + gpointer user_data) +{ + EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (gtk_entry_completion_get_entry (completion)); + EphyTopicsEntryPrivate *priv = entry->priv; + GtkTreeModel *model = gtk_entry_completion_get_model (completion); + + gboolean result; + GValue value = { 0, }; + EphyNode *node; - /* 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 node at all (this happens for unknown reasons) then don't show. */ + gtk_tree_model_get_value (model, iter, COLUMN_NODE, &value); + node = g_value_get_pointer (&value); + if (node == NULL) + { + g_value_unset (&value); + result = FALSE; + } + + /* If it's already selected, don't show it. */ + else if (ephy_node_has_child (node, priv->bookmark)) { - /* If no text to work with, exit */ - key = g_strndup (text+start, end-start); - g_strstrip (key); - if (*key == 0) + g_value_unset (&value); + if (priv->key == NULL) + { + result = FALSE; + } + + /* Unless it's the one we're currently editing. */ + else { - g_free (key); - return; + gtk_tree_model_get_value (model, iter, COLUMN_KEY, &value); + result = (strcmp (g_value_get_string (&value), priv->key) == 0); + g_value_unset (&value); } } - - /* 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); + + /* If it's not selected, assume we show it. */ + else + { + g_value_unset (&value); + if (priv->key == NULL) + { + result = TRUE; + } + + /* Unless it's not matching the current key. */ + else + { + gtk_tree_model_get_value (model, iter, COLUMN_KEY, &value); + result = (g_str_has_prefix (g_value_get_string (&value), priv->key)); + g_value_unset (&value); + } + } + + return result; } static void @@ -340,15 +438,16 @@ action_cb (GtkEntryCompletion *completion, gpointer user_data) { EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (gtk_entry_completion_get_entry (completion)); - char *action = g_strdup(entry->priv->input); - - if (ephy_bookmarks_find_keyword (entry->priv->bookmarks, action, FALSE) == NULL) - { - ephy_bookmarks_add_keyword (entry->priv->bookmarks, action); - } + EphyTopicsEntryPrivate *priv = entry->priv; + char *title; - insert_text (entry, action); - g_free (action); + title = g_strdup (priv->create); + + ephy_bookmarks_add_keyword (priv->bookmarks, title); + update_widget (entry); + + insert_text (entry, title); + g_free (title); } static gboolean @@ -358,22 +457,15 @@ match_selected_cb (GtkEntryCompletion *completion, gpointer user_data) { EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (gtk_entry_completion_get_entry (completion)); - char *title; + GValue value = { 0, }; - gtk_tree_model_get (model, iter, 0, &title, -1); - insert_text (entry, title); - g_free (title); + gtk_tree_model_get_value (model, iter, COLUMN_TITLE, &value); + insert_text (entry, g_value_get_string (&value)); + g_value_unset (&value); return TRUE; } -static void -tree_changed_cb (EphyBookmarks *bookmarks, - EphyTopicsEntry *entry) -{ - update_widget(entry); -} - static gboolean focus_out_cb (GtkEditable *editable, GdkEventFocus *event, @@ -383,40 +475,59 @@ focus_out_cb (GtkEditable *editable, return FALSE; } -static gboolean -match_func (GtkEntryCompletion *completion, - const gchar *key, - GtkTreeIter *iter, - gpointer user_data) +static void +tree_changed_cb (EphyBookmarks *bookmarks, + EphyTopicsEntry *entry) { - GtkEntry *entry = gtk_entry_completion_get_entry (completion); - GtkTreeModel *model = gtk_entry_completion_get_model (completion); - EphyTopicsEntryPrivate *priv = EPHY_TOPICS_ENTRY(entry)->priv; - - gboolean result; - char *text; + update_widget (entry); +} - if (priv->key == NULL) return TRUE; - gtk_tree_model_get (model, iter, 1, &text, -1); - if (text == NULL) return FALSE; - result = g_str_has_prefix (text, priv->key); - g_free (text); - - return result; +static void +node_added_cb (EphyNode *parent, + EphyNode *child, + GObject *object) +{ + update_widget (EPHY_TOPICS_ENTRY (object)); +} + +static void +node_changed_cb (EphyNode *parent, + EphyNode *child, + guint property_id, + GObject *object) +{ + update_widget (EPHY_TOPICS_ENTRY (object)); +} + +static void +node_removed_cb (EphyNode *parent, + EphyNode *child, + guint index, + GObject *object) +{ + update_widget (EPHY_TOPICS_ENTRY (object)); } static void ephy_topics_entry_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) + guint prop_id, + const GValue *value, + GParamSpec *pspec) { EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (object); + EphyNode *node; switch (prop_id) { case PROP_BOOKMARKS: entry->priv->bookmarks = g_value_get_object (value); + node = ephy_bookmarks_get_keywords (entry->priv->bookmarks); + ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_ADDED, + (EphyNodeCallback) node_added_cb, object); + ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_CHANGED, + (EphyNodeCallback) node_changed_cb, object); + ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_REMOVED, + (EphyNodeCallback) node_removed_cb, object); g_signal_connect_object (entry->priv->bookmarks, "tree-changed", G_CALLBACK (tree_changed_cb), entry, G_CONNECT_AFTER); @@ -444,12 +555,11 @@ ephy_topics_entry_constructor (GType type, 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->store = gtk_list_store_new (3, G_TYPE_POINTER, 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_text_column (priv->completion, COLUMN_TITLE); 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); @@ -463,12 +573,12 @@ ephy_topics_entry_constructor (GType type, g_signal_connect (object, "focus-out-event", G_CALLBACK (focus_out_cb), NULL); g_signal_connect (object, "changed", - G_CALLBACK (update_keywords), NULL); + G_CALLBACK (update_database), NULL); g_signal_connect (object, "notify::cursor-position", - G_CALLBACK (update_input), NULL); + G_CALLBACK (update_key), NULL); g_signal_connect (object, "notify::text", - G_CALLBACK (update_input), NULL); + G_CALLBACK (update_key), NULL); update_widget (entry); @@ -487,7 +597,7 @@ ephy_topics_entry_finalize (GObject *object) { EphyTopicsEntry *entry = EPHY_TOPICS_ENTRY (object); - g_free (entry->priv->input); + g_free (entry->priv->create); g_free (entry->priv->key); parent_class->finalize (object); diff --git a/src/bookmarks/ephy-topics-palette.c b/src/bookmarks/ephy-topics-palette.c index 29ff7b0c5..91618699d 100644 --- a/src/bookmarks/ephy-topics-palette.c +++ b/src/bookmarks/ephy-topics-palette.c @@ -269,16 +269,31 @@ tree_changed_cb (EphyBookmarks *bookmarks, g_idle_add ((GSourceFunc) update_list_idle, palette); } +static void +node_added_cb (EphyNode *parent, + EphyNode *child, + EphyTopicsPalette *palette) +{ + g_idle_add ((GSourceFunc) update_list_idle, palette); +} static void -child_changed_cb (EphyNode *node, - EphyNode *child, - guint property_id, - EphyTopicsPalette *palette) +node_changed_cb (EphyNode *parent, + EphyNode *child, + guint property_id, + EphyTopicsPalette *palette) { g_idle_add ((GSourceFunc) update_list_idle, palette); } +static void +node_removed_cb (EphyNode *parent, + EphyNode *child, + guint index, + EphyTopicsPalette *palette) +{ + g_idle_add ((GSourceFunc) update_list_idle, palette); +} static void ephy_topics_palette_set_property (GObject *object, @@ -287,17 +302,22 @@ ephy_topics_palette_set_property (GObject *object, GParamSpec *pspec) { EphyTopicsPalette *palette = EPHY_TOPICS_PALETTE (object); + EphyNode *node; switch (prop_id) { case PROP_BOOKMARKS: palette->priv->bookmarks = g_value_get_object (value); + node = ephy_bookmarks_get_keywords (palette->priv->bookmarks); + ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_ADDED, + (EphyNodeCallback) node_added_cb, object); + ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_CHANGED, + (EphyNodeCallback) node_changed_cb, object); + ephy_node_signal_connect_object (node, EPHY_NODE_CHILD_REMOVED, + (EphyNodeCallback) node_removed_cb, object); g_signal_connect_object (palette->priv->bookmarks, "tree-changed", G_CALLBACK (tree_changed_cb), palette, G_CONNECT_AFTER); - ephy_node_signal_connect_object - (ephy_bookmarks_get_keywords (palette->priv->bookmarks), - EPHY_NODE_CHILD_CHANGED, (EphyNodeCallback) child_changed_cb, object); break; case PROP_BOOKMARK: palette->priv->bookmark = g_value_get_pointer (value); |