gimp r26052 - in branches/soc-2008-tagging: . app/core app/widgets
- From: aurisj svn gnome org
- To: svn-commits-list gnome org
- Subject: gimp r26052 - in branches/soc-2008-tagging: . app/core app/widgets
- Date: Thu, 3 Jul 2008 22:20:33 +0000 (UTC)
Author: aurisj
Date: Thu Jul 3 22:20:32 2008
New Revision: 26052
URL: http://svn.gnome.org/viewvc/gimp?rev=26052&view=rev
Log:
2008-07-04 Aurimas JuÅka <aurisj svn gnome org>
* app/widgets/gimptagentry.c: support tag autocompletion.
* app/core/gimpfilteredcontainer.[ch]: maintain tag reference count
of all items contained in source container.
Modified:
branches/soc-2008-tagging/ChangeLog
branches/soc-2008-tagging/app/core/gimpfilteredcontainer.c
branches/soc-2008-tagging/app/core/gimpfilteredcontainer.h
branches/soc-2008-tagging/app/widgets/gimptagentry.c
Modified: branches/soc-2008-tagging/app/core/gimpfilteredcontainer.c
==============================================================================
--- branches/soc-2008-tagging/app/core/gimpfilteredcontainer.c (original)
+++ branches/soc-2008-tagging/app/core/gimpfilteredcontainer.c Thu Jul 3 22:20:32 2008
@@ -53,6 +53,16 @@
GimpFilteredContainer *filtered_container);
static void gimp_filtered_container_src_thaw (GimpContainer *src_container,
GimpFilteredContainer *filtered_container);
+static void gimp_filtered_container_tag_added (GimpTagged *tagged,
+ GimpTag tag,
+ GimpFilteredContainer *filtered_container);
+static void gimp_filtered_container_tag_removed (GimpTagged *tagged,
+ GimpTag tag,
+ GimpFilteredContainer *filtered_container);
+static void gimp_filtered_container_tagged_item_added (GimpTagged *tagged,
+ GimpFilteredContainer *filtered_container);
+static void gimp_filtered_container_tagged_item_removed(GimpTagged *tagged,
+ GimpFilteredContainer *filtered_container);
G_DEFINE_TYPE (GimpFilteredContainer, gimp_filtered_container, GIMP_TYPE_LIST)
@@ -76,6 +86,7 @@
{
filtered_container->src_container = NULL;
filtered_container->filter = NULL;
+ filtered_container->tag_ref_counts = NULL;
}
static void
@@ -136,6 +147,7 @@
filtered_container->src_container = src_container;
GIMP_CONTAINER (filtered_container)->children_type = children_type;
+ filtered_container->tag_ref_counts = g_hash_table_new (g_direct_hash, g_direct_equal);
gimp_filtered_container_filter (filtered_container);
@@ -220,6 +232,9 @@
gimp_filtered_container_filter (GimpFilteredContainer *filtered_container)
{
gimp_container_foreach (filtered_container->src_container,
+ (GFunc) gimp_filtered_container_tagged_item_added,
+ filtered_container);
+ gimp_container_foreach (filtered_container->src_container,
(GFunc) add_filtered_item, filtered_container);
}
@@ -228,6 +243,9 @@
GimpObject *obj,
GimpFilteredContainer *filtered_container)
{
+ gimp_filtered_container_tagged_item_added (GIMP_TAGGED (obj),
+ filtered_container);
+
if (! gimp_container_frozen (src_container))
{
gimp_container_add (GIMP_CONTAINER (filtered_container), obj);
@@ -239,6 +257,9 @@
GimpObject *obj,
GimpFilteredContainer *filtered_container)
{
+ gimp_filtered_container_tagged_item_removed (GIMP_TAGGED (obj),
+ filtered_container);
+
if (! gimp_container_frozen (src_container)
&& gimp_container_have (GIMP_CONTAINER (filtered_container), obj))
{
@@ -250,8 +271,9 @@
gimp_filtered_container_src_freeze (GimpContainer *src_container,
GimpFilteredContainer *filtered_container)
{
- gimp_container_clear (GIMP_CONTAINER (filtered_container));
gimp_container_freeze (GIMP_CONTAINER (filtered_container));
+ gimp_container_clear (GIMP_CONTAINER (filtered_container));
+ g_hash_table_remove_all (filtered_container->tag_ref_counts);
}
static void
@@ -261,3 +283,88 @@
gimp_filtered_container_filter (filtered_container);
gimp_container_thaw (GIMP_CONTAINER (filtered_container));
}
+
+static void
+gimp_filtered_container_tagged_item_added (GimpTagged *tagged,
+ GimpFilteredContainer *filtered_container)
+{
+ GList *tag_iterator;
+
+ tag_iterator = gimp_tagged_get_tags (tagged);
+ while (tag_iterator)
+ {
+ gimp_filtered_container_tag_added (tagged,
+ GPOINTER_TO_UINT (tag_iterator->data),
+ filtered_container);
+ tag_iterator = g_list_next (tag_iterator);
+ }
+
+ g_signal_connect (tagged, "tag-added",
+ G_CALLBACK (gimp_filtered_container_tag_added),
+ filtered_container);
+ g_signal_connect (tagged, "tag-removed",
+ G_CALLBACK (gimp_filtered_container_tag_removed),
+ filtered_container);
+}
+
+static void
+gimp_filtered_container_tagged_item_removed (GimpTagged *tagged,
+ GimpFilteredContainer *filtered_container)
+{
+ GList *tag_iterator;
+
+ g_signal_handlers_disconnect_by_func (tagged,
+ G_CALLBACK (gimp_filtered_container_tag_added),
+ filtered_container);
+ g_signal_handlers_disconnect_by_func (tagged,
+ G_CALLBACK (gimp_filtered_container_tag_removed),
+ filtered_container);
+
+ tag_iterator = gimp_tagged_get_tags (tagged);
+ while (tag_iterator)
+ {
+ gimp_filtered_container_tag_removed (tagged,
+ GPOINTER_TO_UINT (tag_iterator->data),
+ filtered_container);
+ tag_iterator = g_list_next (tag_iterator);
+ }
+
+}
+
+static void
+gimp_filtered_container_tag_added (GimpTagged *tagged,
+ GimpTag tag,
+ GimpFilteredContainer *filtered_container)
+{
+ gint ref_count;
+
+ ref_count = GPOINTER_TO_INT (g_hash_table_lookup (filtered_container->tag_ref_counts,
+ GUINT_TO_POINTER (tag)));
+ ref_count++;
+ g_hash_table_insert (filtered_container->tag_ref_counts,
+ GUINT_TO_POINTER (tag),
+ GINT_TO_POINTER (ref_count));
+}
+
+static void
+gimp_filtered_container_tag_removed (GimpTagged *tagged,
+ GimpTag tag,
+ GimpFilteredContainer *filtered_container)
+{
+ gint ref_count;
+
+ ref_count = GPOINTER_TO_INT (g_hash_table_lookup (filtered_container->tag_ref_counts,
+ GUINT_TO_POINTER (tag)));
+ ref_count--;
+ if (ref_count > 0)
+ {
+ g_hash_table_insert (filtered_container->tag_ref_counts,
+ GUINT_TO_POINTER (tag),
+ GINT_TO_POINTER (ref_count));
+ }
+ else
+ {
+ g_hash_table_remove (filtered_container->tag_ref_counts,
+ GUINT_TO_POINTER (tag));
+ }
+}
Modified: branches/soc-2008-tagging/app/core/gimpfilteredcontainer.h
==============================================================================
--- branches/soc-2008-tagging/app/core/gimpfilteredcontainer.h (original)
+++ branches/soc-2008-tagging/app/core/gimpfilteredcontainer.h Thu Jul 3 22:20:32 2008
@@ -41,6 +41,7 @@
GimpContainer *src_container;
GList *filter;
+ GHashTable *tag_ref_counts;
};
struct _GimpFilteredContainerClass
Modified: branches/soc-2008-tagging/app/widgets/gimptagentry.c
==============================================================================
--- branches/soc-2008-tagging/app/widgets/gimptagentry.c (original)
+++ branches/soc-2008-tagging/app/widgets/gimptagentry.c Thu Jul 3 22:20:32 2008
@@ -35,10 +35,17 @@
#include "gimptagentry.h"
+#define TAG_SEPARATOR_STR ","
+
static void gimp_tag_entry_activate (GtkEntry *entry,
gpointer unused);
static void gimp_tag_entry_changed (GtkEntry *entry,
gpointer unused);
+static void gimp_tag_entry_insert_text (GtkEditable *editable,
+ gchar *new_text,
+ gint text_length,
+ gint *position,
+ gpointer user_data);
static void gimp_tag_entry_query_tag (GimpTagEntry *entry);
@@ -50,6 +57,16 @@
static gchar ** gimp_tag_entry_parse_tags (GimpTagEntry *entry);
+static gchar* gimp_tag_entry_get_completion_prefix (GimpTagEntry *entry);
+static GList * gimp_tag_entry_get_completion_candidates (GimpTagEntry *tag_entry,
+ gchar **used_tags,
+ gchar *prefix);
+static gchar * gimp_tag_entry_get_completion_string (GimpTagEntry *tag_entry,
+ GList *candidates,
+ gchar *prefix);
+static gboolean gimp_tag_entry_auto_complete (GimpTagEntry *tag_entry);
+
+
G_DEFINE_TYPE (GimpTagEntry, gimp_tag_entry, GTK_TYPE_ENTRY);
#define parent_class gimp_tag_entry_parent_class
@@ -65,7 +82,7 @@
gimp_tag_entry_init (GimpTagEntry *entry)
{
entry->tagged_container = NULL;
- entry->selected_items = NULL;
+ entry->selected_items = NULL;
entry->mode = GIMP_TAG_ENTRY_MODE_QUERY;
g_signal_connect (entry, "activate",
@@ -74,6 +91,9 @@
g_signal_connect (entry, "changed",
G_CALLBACK (gimp_tag_entry_changed),
NULL);
+ g_signal_connect (entry, "insert-text",
+ G_CALLBACK (gimp_tag_entry_insert_text),
+ NULL);
}
GtkWidget *
@@ -98,9 +118,20 @@
gpointer unused)
{
GimpTagEntry *tag_entry;
+ gint selection_start;
+ gint selection_end;
tag_entry = GIMP_TAG_ENTRY (entry);
+ gtk_editable_get_selection_bounds (GTK_EDITABLE (entry),
+ &selection_start, &selection_end);
+ if (selection_start != selection_end)
+ {
+ gtk_editable_select_region (GTK_EDITABLE (entry),
+ selection_end, selection_end);
+ return;
+ }
+
if (tag_entry->mode == GIMP_TAG_ENTRY_MODE_ASSIGN)
{
gimp_tag_entry_assign_tags (GIMP_TAG_ENTRY (entry));
@@ -122,6 +153,17 @@
}
static void
+gimp_tag_entry_insert_text (GtkEditable *editable,
+ gchar *new_text,
+ gint text_length,
+ gint *position,
+ gpointer user_data)
+{
+ g_idle_add ((GSourceFunc)gimp_tag_entry_auto_complete,
+ editable);
+}
+
+static void
gimp_tag_entry_query_tag (GimpTagEntry *entry)
{
GimpTagEntry *tag_entry;
@@ -147,6 +189,51 @@
query_list);
}
+static gboolean
+gimp_tag_entry_auto_complete (GimpTagEntry *tag_entry)
+{
+ gchar *completion_prefix;
+ GList *completion_candidates;
+ gchar **tags;
+ gchar *completion;
+ gint start_position;
+ gint end_position;
+ GtkEntry *entry;
+
+ entry = GTK_ENTRY (tag_entry);
+
+ completion_prefix =
+ gimp_tag_entry_get_completion_prefix (GIMP_TAG_ENTRY (entry));
+ tags = gimp_tag_entry_parse_tags (GIMP_TAG_ENTRY (entry));
+ completion_candidates =
+ gimp_tag_entry_get_completion_candidates (GIMP_TAG_ENTRY (entry),
+ tags,
+ completion_prefix);
+ completion =
+ gimp_tag_entry_get_completion_string (GIMP_TAG_ENTRY (entry),
+ completion_candidates,
+ completion_prefix);
+
+ if (completion
+ && strlen (completion) > 0)
+ {
+ start_position = gtk_editable_get_position (GTK_EDITABLE (entry));
+ end_position = start_position;
+ gtk_editable_insert_text (GTK_EDITABLE (entry),
+ completion, strlen (completion),
+ &end_position);
+ gtk_editable_select_region (GTK_EDITABLE (entry),
+ start_position, end_position);
+ }
+
+ g_free (completion);
+ g_strfreev (tags);
+ g_list_free (completion_candidates);
+ g_free (completion_prefix);
+
+ return FALSE;
+}
+
static void
gimp_tag_entry_assign_tags (GimpTagEntry *tag_entry)
{
@@ -276,3 +363,171 @@
}
}
+static gchar*
+gimp_tag_entry_get_completion_prefix (GimpTagEntry *entry)
+{
+ gchar *original_string;
+ gchar *prefix_start;
+ gchar *prefix;
+ gchar *cursor;
+ gint position;
+ gint i;
+ gunichar separator;
+ gunichar c;
+
+ original_string = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
+ position = gtk_editable_get_position (GTK_EDITABLE (entry));
+ cursor = original_string;
+ prefix_start = original_string;
+ separator = g_utf8_get_char (TAG_SEPARATOR_STR);
+ for (i = 0; i < position; i++)
+ {
+ c = g_utf8_get_char (cursor);
+ cursor = g_utf8_next_char (cursor);
+ if (c == separator)
+ {
+ prefix_start = cursor;
+ }
+ }
+ do
+ {
+ c = g_utf8_get_char (cursor);
+ if (c == separator)
+ {
+ *cursor = '\0';
+ break;
+ }
+ cursor = g_utf8_next_char (cursor);
+ } while (c);
+
+ prefix = g_strdup (g_strstrip (prefix_start));
+ g_free (original_string);
+
+ return prefix;
+}
+
+static GList *
+gimp_tag_entry_get_completion_candidates (GimpTagEntry *tag_entry,
+ gchar **used_tags,
+ gchar *prefix)
+{
+ GList *candidates = NULL;
+ GList *all_tags;
+ GList *tag_iterator;
+ GimpTag tag;
+ gint i;
+ gint length;
+
+ if (!prefix
+ || strlen (prefix) < 1)
+ {
+ return NULL;
+ }
+
+ all_tags = g_hash_table_get_keys (tag_entry->tagged_container->tag_ref_counts);
+ tag_iterator = all_tags;
+ length = g_strv_length (used_tags);
+ while (tag_iterator)
+ {
+ tag = GPOINTER_TO_UINT (tag_iterator->data);
+ if (g_str_has_prefix (g_quark_to_string (tag), prefix))
+ {
+ /* check if tag is not already entered */
+ for (i = 0; i < length; i++)
+ {
+ if (! strcmp (g_quark_to_string (tag), used_tags[i]))
+ {
+ break;
+ }
+ }
+
+ if (i == length)
+ {
+ candidates = g_list_append (candidates, tag_iterator->data);
+ }
+ }
+ tag_iterator = g_list_next (tag_iterator);
+ }
+ g_list_free (all_tags);
+
+ return candidates;
+}
+
+static gchar *
+gimp_tag_entry_get_completion_string (GimpTagEntry *tag_entry,
+ GList *candidates,
+ gchar *prefix)
+{
+ const gchar **completions;
+ guint length;
+ guint i;
+ GList *candidate_iterator;
+ const gchar *candidate_string;
+ gint prefix_length;
+ gunichar c;
+ gunichar d;
+ gint num_chars_match;
+ gchar *completion;
+ gchar *completion_end;
+ gint completion_length;
+
+ if (! candidates)
+ {
+ return NULL;
+ }
+
+ prefix_length = strlen (prefix);
+ length = g_list_length (candidates);
+ if (length < 2)
+ {
+ candidate_string = g_quark_to_string (GPOINTER_TO_UINT (candidates->data));
+ return g_strdup (candidate_string + prefix_length);
+ }
+
+ completions = g_malloc (length * sizeof (gchar*));
+ candidate_iterator = candidates;
+ for (i = 0; i < length; i++)
+ {
+ candidate_string =
+ g_quark_to_string (GPOINTER_TO_UINT (candidate_iterator->data));
+ completions[i] = candidate_string + prefix_length;
+ candidate_iterator = g_list_next (candidate_iterator);
+ }
+
+ num_chars_match = 0;
+ do
+ {
+ c = g_utf8_get_char (completions[0]);
+ if (!c)
+ {
+ break;
+ }
+
+ for (i = 1; i < length; i++)
+ {
+ d = g_utf8_get_char (completions[i]);
+ if (c != d)
+ {
+ candidate_string = g_quark_to_string (GPOINTER_TO_UINT (candidates->data));
+ candidate_string += prefix_length;
+ completion_end = g_utf8_offset_to_pointer (candidate_string,
+ num_chars_match);
+ completion_length = completion_end - candidate_string;
+ completion = g_malloc (completion_length + 1);
+ memcpy (completion, candidate_string, completion_length);
+ completion[completion_length] = '\0';
+
+ g_free (completions);
+ return completion;
+ }
+ completions[i] = g_utf8_next_char (completions[i]);
+ }
+ completions[0] = g_utf8_next_char (completions[0]);
+ num_chars_match++;
+ } while (c);
+ g_free (completions);
+
+ candidate_string = g_quark_to_string (GPOINTER_TO_UINT (candidates->data));
+ return g_strdup (candidate_string + prefix_length);
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]