]> git.0d.be Git - empathy.git/commitdiff
live-search: move from Empathy to tp-account-widgets
authorMarco Barisione <marco.barisione@collabora.co.uk>
Thu, 9 May 2013 12:44:04 +0000 (13:44 +0100)
committerMarco Barisione <marco.barisione@collabora.co.uk>
Tue, 20 Aug 2013 10:03:05 +0000 (11:03 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=699492

19 files changed:
libempathy-gtk/Makefile.am
libempathy-gtk/empathy-contact-chooser.c
libempathy-gtk/empathy-individual-view.c
libempathy-gtk/empathy-individual-view.h
libempathy-gtk/empathy-live-search.c [deleted file]
libempathy-gtk/empathy-live-search.h [deleted file]
libempathy-gtk/empathy-roster-view.c
libempathy-gtk/empathy-roster-view.h
libempathy-gtk/empathy-ui-utils.c
src/empathy-roster-window.c
tests/empathy-live-search-test.c
tests/interactive/Makefile.am
tests/interactive/test-empathy-dual-roster-view.c
tests/interactive/test-empathy-roster-model-aggregator.c
tests/interactive/test-empathy-roster-view.c
tp-account-widgets/Makefile.am
tp-account-widgets/tpaw-irc-network-chooser-dialog.c
tp-account-widgets/tpaw-live-search.c [new file with mode: 0644]
tp-account-widgets/tpaw-live-search.h [new file with mode: 0644]

index 3605eea78be8fa24de66a173e5ec44db8be42a9d..43e768913dda0562bc894d2db96a9d633bce1b2a 100644 (file)
@@ -42,7 +42,6 @@ libempathy_gtk_handwritten_source =                   \
        empathy-contact-blocking-dialog.c       \
        empathy-contact-chooser.c               \
        empathy-contactinfo-utils.c             \
-       empathy-live-search.c                   \
        empathy-contact-search-dialog.c         \
        empathy-contact-widget.c                \
        empathy-dialpad-widget.c                \
@@ -106,7 +105,6 @@ libempathy_gtk_headers =                    \
        empathy-chat.h                          \
        empathy-contact-blocking-dialog.h       \
        empathy-contact-chooser.h               \
-       empathy-live-search.h                   \
        empathy-contact-search-dialog.h         \
        empathy-contact-widget.h                \
        empathy-contactinfo-utils.h             \
index dd81dde419c38e5c11ad9b8a1c11f8a4abeed3a1..e31b22fe11cc5e9d8b98975c4d43955426a4a051 100644 (file)
@@ -312,7 +312,7 @@ search_text_changed (GtkEntry *entry,
 
   id = gtk_entry_get_text (entry);
 
-  self->priv->search_words = empathy_live_search_strip_utf8_string (id);
+  self->priv->search_words = tpaw_live_search_strip_utf8_string (id);
   self->priv->search_str = g_strdup (id);
 
   add_temporary_individuals (self, id);
index d0a367df2510882b4a3721efa879f4df8d9e7aff..8fe7af727c398a9cd5868b3e786d1b94404a2b9d 100644 (file)
@@ -1327,7 +1327,7 @@ individual_view_start_search_cb (EmpathyIndividualView *view,
 }
 
 static void
-individual_view_search_text_notify_cb (EmpathyLiveSearch *search,
+individual_view_search_text_notify_cb (TpawLiveSearch *search,
     GParamSpec *pspec,
     EmpathyIndividualView *view)
 {
@@ -1420,7 +1420,7 @@ individual_view_search_key_navigation_cb (GtkWidget *search,
 }
 
 static void
-individual_view_search_hide_cb (EmpathyLiveSearch *search,
+individual_view_search_hide_cb (TpawLiveSearch *search,
     EmpathyIndividualView *view)
 {
   EmpathyIndividualViewPriv *priv = GET_PRIV (view);
@@ -1489,7 +1489,7 @@ individual_view_search_hide_cb (EmpathyLiveSearch *search,
 }
 
 static void
-individual_view_search_show_cb (EmpathyLiveSearch *search,
+individual_view_search_show_cb (TpawLiveSearch *search,
     EmpathyIndividualView *view)
 {
   /* block expand or collapse handlers during expand all, they would
@@ -1639,7 +1639,7 @@ individual_view_is_visible_individual (EmpathyIndividualView *self,
     guint event_count)
 {
   EmpathyIndividualViewPriv *priv = GET_PRIV (self);
-  EmpathyLiveSearch *live = EMPATHY_LIVE_SEARCH (priv->search_widget);
+  TpawLiveSearch *live = TPAW_LIVE_SEARCH (priv->search_widget);
   GeeSet *personas;
   GeeIterator *iter;
   gboolean is_favorite;
@@ -1691,8 +1691,8 @@ individual_view_is_visible_individual (EmpathyIndividualView *self,
   }
 
   return empathy_individual_match_string (individual,
-      empathy_live_search_get_text (live),
-      empathy_live_search_get_words (live));
+      tpaw_live_search_get_text (live),
+      tpaw_live_search_get_words (live));
 }
 
 static gchar *
@@ -2483,7 +2483,7 @@ out:
 
 void
 empathy_individual_view_set_live_search (EmpathyIndividualView *view,
-    EmpathyLiveSearch *search)
+    TpawLiveSearch *search)
 {
   EmpathyIndividualViewPriv *priv = GET_PRIV (view);
 
index e942a42b50dbb176a7c852acf258e2399f957cfd..2fd0bce5fbd056a76228e7b9aaec59bc37a49057 100644 (file)
 
 #include <gtk/gtk.h>
 #include <folks/folks.h>
+#include <tp-account-widgets/tpaw-live-search.h>
 
 #include "empathy-individual-menu.h"
 #include "empathy-individual-store.h"
-#include "empathy-live-search.h"
 
 G_BEGIN_DECLS
 #define EMPATHY_TYPE_INDIVIDUAL_VIEW         (empathy_individual_view_get_type ())
@@ -100,7 +100,7 @@ GtkWidget *empathy_individual_view_get_individual_menu (
 GtkWidget *empathy_individual_view_get_group_menu (EmpathyIndividualView *view);
 
 void empathy_individual_view_set_live_search (EmpathyIndividualView *view,
-    EmpathyLiveSearch *search);
+    TpawLiveSearch *search);
 
 gboolean empathy_individual_view_get_show_offline (
     EmpathyIndividualView *view);
diff --git a/libempathy-gtk/empathy-live-search.c b/libempathy-gtk/empathy-live-search.c
deleted file mode 100644 (file)
index 51f6a2e..0000000
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * Copyright (C) 2010 Collabora Ltd.
- * Copyright (C) 2007-2010 Nokia Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * Authors: Felix Kaser <felix.kaser@collabora.co.uk>
- *          Xavier Claessens <xavier.claessens@collabora.co.uk>
- *          Claudio Saavedra <csaavedra@igalia.com>
- */
-
-#include "config.h"
-#include "empathy-live-search.h"
-
-#include "empathy-utils.h"
-
-G_DEFINE_TYPE (EmpathyLiveSearch, empathy_live_search, GTK_TYPE_HBOX)
-
-#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLiveSearch)
-
-typedef struct
-{
-  GtkWidget *search_entry;
-  GtkWidget *hook_widget;
-
-  GPtrArray *stripped_words;
-} EmpathyLiveSearchPriv;
-
-enum
-{
-  PROP_0,
-  PROP_HOOK_WIDGET,
-  PROP_TEXT
-};
-
-enum
-{
-  ACTIVATE,
-  KEYNAV,
-  LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL];
-
-static void live_search_hook_widget_destroy_cb (GtkWidget *object,
-    gpointer user_data);
-
-/**
- * stripped_char:
- *
- * Returns a stripped version of @ch, removing any case, accentuation
- * mark, or any special mark on it.
- **/
-static gunichar
-stripped_char (gunichar ch)
-{
-  gunichar retval = 0;
-  GUnicodeType utype;
-
-  utype = g_unichar_type (ch);
-
-  switch (utype)
-    {
-    case G_UNICODE_CONTROL:
-    case G_UNICODE_FORMAT:
-    case G_UNICODE_UNASSIGNED:
-    case G_UNICODE_NON_SPACING_MARK:
-    case G_UNICODE_COMBINING_MARK:
-    case G_UNICODE_ENCLOSING_MARK:
-      /* Ignore those */
-      break;
-    case G_UNICODE_PRIVATE_USE:
-    case G_UNICODE_SURROGATE:
-    case G_UNICODE_LOWERCASE_LETTER:
-    case G_UNICODE_MODIFIER_LETTER:
-    case G_UNICODE_OTHER_LETTER:
-    case G_UNICODE_TITLECASE_LETTER:
-    case G_UNICODE_UPPERCASE_LETTER:
-    case G_UNICODE_DECIMAL_NUMBER:
-    case G_UNICODE_LETTER_NUMBER:
-    case G_UNICODE_OTHER_NUMBER:
-    case G_UNICODE_CONNECT_PUNCTUATION:
-    case G_UNICODE_DASH_PUNCTUATION:
-    case G_UNICODE_CLOSE_PUNCTUATION:
-    case G_UNICODE_FINAL_PUNCTUATION:
-    case G_UNICODE_INITIAL_PUNCTUATION:
-    case G_UNICODE_OTHER_PUNCTUATION:
-    case G_UNICODE_OPEN_PUNCTUATION:
-    case G_UNICODE_CURRENCY_SYMBOL:
-    case G_UNICODE_MODIFIER_SYMBOL:
-    case G_UNICODE_MATH_SYMBOL:
-    case G_UNICODE_OTHER_SYMBOL:
-    case G_UNICODE_LINE_SEPARATOR:
-    case G_UNICODE_PARAGRAPH_SEPARATOR:
-    case G_UNICODE_SPACE_SEPARATOR:
-    default:
-      ch = g_unichar_tolower (ch);
-      g_unichar_fully_decompose (ch, FALSE, &retval, 1);
-    }
-
-  return retval;
-}
-
-static void
-append_word (GPtrArray **word_array,
-    GString **word)
-{
-  if (*word != NULL)
-    {
-      if (*word_array == NULL)
-        *word_array = g_ptr_array_new_with_free_func (g_free);
-      g_ptr_array_add (*word_array, g_string_free (*word, FALSE));
-      *word = NULL;
-    }
-}
-
-GPtrArray *
-empathy_live_search_strip_utf8_string (const gchar *string)
-{
-  GPtrArray *word_array = NULL;
-  GString *word = NULL;
-  const gchar *p;
-
-  if (EMP_STR_EMPTY (string))
-    return NULL;
-
-  for (p = string; *p != '\0'; p = g_utf8_next_char (p))
-    {
-      gunichar sc;
-
-      /* Make the char lower-case, remove its accentuation marks, and ignore it
-       * if it is just unicode marks */
-      sc = stripped_char (g_utf8_get_char (p));
-      if (sc == 0)
-        continue;
-
-      /* If it is not alpha-num, it is separator between words */
-      if (!g_unichar_isalnum (sc))
-        {
-          append_word (&word_array, &word);
-          continue;
-        }
-
-      /* It is alpha-num, append this char to current word, or start new word */
-      if (word == NULL)
-        word = g_string_new (NULL);
-      g_string_append_unichar (word, sc);
-    }
-
-  append_word (&word_array, &word);
-
-  return word_array;
-}
-
-static gboolean
-live_search_match_prefix (const gchar *string,
-    const gchar *prefix)
-{
-  const gchar *p;
-  const gchar *prefix_p;
-  gboolean next_word = FALSE;
-
-  if (prefix == NULL || prefix[0] == 0)
-    return TRUE;
-
-  if (EMP_STR_EMPTY (string))
-    return FALSE;
-
-  prefix_p = prefix;
-  for (p = string; *p != '\0'; p = g_utf8_next_char (p))
-    {
-      gunichar sc;
-
-      /* Make the char lower-case, remove its accentuation marks, and ignore it
-       * if it is just unicode marks */
-      sc = stripped_char (g_utf8_get_char (p));
-      if (sc == 0)
-        continue;
-
-      /* If we want to go to next word, ignore alpha-num chars */
-      if (next_word && g_unichar_isalnum (sc))
-        continue;
-      next_word = FALSE;
-
-      /* Ignore word separators */
-      if (!g_unichar_isalnum (sc))
-        continue;
-
-      /* If this char does not match prefix_p, go to next word and start again
-       * from the beginning of prefix */
-      if (sc != g_utf8_get_char (prefix_p))
-        {
-          next_word = TRUE;
-          prefix_p = prefix;
-          continue;
-        }
-
-      /* prefix_p match, verify to next char. If this was the last of prefix,
-       * it means it completely machted and we are done. */
-      prefix_p = g_utf8_next_char (prefix_p);
-      if (*prefix_p == '\0')
-        return TRUE;
-    }
-
-  return FALSE;
-}
-
-gboolean
-empathy_live_search_match_words (const gchar *string,
-    GPtrArray *words)
-{
-  guint i;
-
-  if (words == NULL)
-    return TRUE;
-
-  for (i = 0; i < words->len; i++)
-    if (!live_search_match_prefix (string, g_ptr_array_index (words, i)))
-      return FALSE;
-
-  return TRUE;
-}
-
-static gboolean
-fire_key_navigation_sig (EmpathyLiveSearch *self,
-    GdkEventKey *event)
-{
-  gboolean ret;
-
-  g_signal_emit (self, signals[KEYNAV], 0, event, &ret);
-  return ret;
-}
-
-static gboolean
-live_search_entry_key_pressed_cb (GtkEntry *entry,
-    GdkEventKey *event,
-    gpointer user_data)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (user_data);
-
-  /* if esc key pressed, hide the search */
-  if (event->keyval == GDK_KEY_Escape)
-    {
-      gtk_widget_hide (GTK_WIDGET (self));
-      return TRUE;
-    }
-
-  /* emit key navigation signal, so other widgets can respond to it properly */
-  if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down
-      || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down
-      || event->keyval == GDK_KEY_Menu)
-     {
-       return fire_key_navigation_sig (self, event);
-     }
-
-  if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End ||
-      event->keyval == GDK_KEY_space)
-    {
-      /* If the live search is visible, the entry should catch the Home/End
-       * and space events */
-      if (!gtk_widget_get_visible (GTK_WIDGET (self)))
-        {
-          return fire_key_navigation_sig (self, event);
-        }
-    }
-
-  return FALSE;
-}
-
-static void
-live_search_text_changed (GtkEntry *entry,
-    gpointer user_data)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (user_data);
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-  const gchar *text;
-
-  text = gtk_entry_get_text (entry);
-
-  if (EMP_STR_EMPTY (text))
-    gtk_widget_hide (GTK_WIDGET (self));
-  else
-    gtk_widget_show (GTK_WIDGET (self));
-
-  if (priv->stripped_words != NULL)
-    g_ptr_array_unref (priv->stripped_words);
-
-  priv->stripped_words = empathy_live_search_strip_utf8_string (text);
-
-  g_object_notify (G_OBJECT (self), "text");
-}
-
-static void
-live_search_close_pressed (GtkEntry *entry,
-    GtkEntryIconPosition icon_pos,
-    GdkEvent *event,
-    gpointer user_data)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (user_data);
-
-  gtk_widget_hide (GTK_WIDGET (self));
-}
-
-static gboolean
-live_search_key_press_event_cb (GtkWidget *widget,
-    GdkEventKey *event,
-    gpointer user_data)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (user_data);
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-  GdkEvent *new_event;
-  gboolean ret;
-
-  /* dont forward this event to the entry, else the event is consumed by the
-   * entry and does not close the window */
-  if (!gtk_widget_get_visible (GTK_WIDGET (self)) &&
-      event->keyval == GDK_KEY_Escape)
-    return FALSE;
-
-  /* do not show the search if CTRL and/or ALT are pressed with a key
-   * this is needed, because otherwise the CTRL + F accel would not work,
-   * because the entry consumes it */
-  if (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK) ||
-      event->keyval == GDK_KEY_Control_L ||
-      event->keyval == GDK_KEY_Control_R)
-    return FALSE;
-
-  /* dont forward the up/down and Page Up/Down arrow keys to the entry,
-   * they are needed for navigation in the treeview and are not needed in
-   * the search entry */
-   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down ||
-       event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down ||
-       event->keyval == GDK_KEY_Menu)
-     return FALSE;
-
-   if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End ||
-       event->keyval == GDK_KEY_space)
-     {
-       /* Home/End and space keys have to be forwarded to the entry only if
-        * the live search is visible (to move the cursor inside the entry). */
-       if (!gtk_widget_get_visible (GTK_WIDGET (self)))
-         return FALSE;
-     }
-
-   /* Don't forward shift keys events as focusing the search entry would
-    * cancel an in-progress editing on a cell renderer (like when renaming a
-    * group). There is no point focusing it anyway as we don't display the
-    * search entry when only a shift key is pressed. */
-   if (event->keyval == GDK_KEY_Shift_L ||
-       event->keyval == GDK_KEY_Shift_R)
-       return FALSE;
-
-  /* realize the widget if it is not realized yet */
-  gtk_widget_realize (priv->search_entry);
-  if (!gtk_widget_has_focus (priv->search_entry))
-    {
-      gtk_widget_grab_focus (priv->search_entry);
-      gtk_editable_set_position (GTK_EDITABLE (priv->search_entry), -1);
-    }
-
-  /* forward the event to the search entry */
-  new_event = gdk_event_copy ((GdkEvent *) event);
-  ret = gtk_widget_event (priv->search_entry, new_event);
-  gdk_event_free (new_event);
-
-  return ret;
-}
-
-static void
-live_search_entry_activate_cb (GtkEntry *entry,
-    EmpathyLiveSearch *self)
-{
-  g_signal_emit (self, signals[ACTIVATE], 0);
-}
-
-static void
-live_search_release_hook_widget (EmpathyLiveSearch *self)
-{
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  /* remove old handlers if old source was not null */
-  if (priv->hook_widget != NULL)
-    {
-      g_signal_handlers_disconnect_by_func (priv->hook_widget,
-          live_search_key_press_event_cb, self);
-      g_signal_handlers_disconnect_by_func (priv->hook_widget,
-          live_search_hook_widget_destroy_cb, self);
-      g_object_unref (priv->hook_widget);
-      priv->hook_widget = NULL;
-    }
-}
-
-static void
-live_search_hook_widget_destroy_cb (GtkWidget *object,
-    gpointer user_data)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (user_data);
-
-  /* unref the hook widget and hide search */
-  gtk_widget_hide (GTK_WIDGET (self));
-  live_search_release_hook_widget (self);
-}
-
-static void
-live_search_dispose (GObject *obj)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (obj);
-
-  live_search_release_hook_widget (self);
-
-  if (G_OBJECT_CLASS (empathy_live_search_parent_class)->dispose != NULL)
-    G_OBJECT_CLASS (empathy_live_search_parent_class)->dispose (obj);
-}
-
-static void
-live_search_finalize (GObject *obj)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (obj);
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  if (priv->stripped_words != NULL)
-    g_ptr_array_unref (priv->stripped_words);
-
-  if (G_OBJECT_CLASS (empathy_live_search_parent_class)->finalize != NULL)
-    G_OBJECT_CLASS (empathy_live_search_parent_class)->finalize (obj);
-}
-
-static void
-live_search_get_property (GObject *object,
-    guint param_id,
-    GValue *value,
-    GParamSpec *pspec)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (object);
-
-  switch (param_id)
-    {
-    case PROP_HOOK_WIDGET:
-      g_value_set_object (value, empathy_live_search_get_hook_widget (self));
-      break;
-    case PROP_TEXT:
-      g_value_set_string (value, empathy_live_search_get_text (self));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-      break;
-    }
-}
-
-static void
-live_search_set_property (GObject *object,
-    guint param_id,
-    const GValue *value,
-    GParamSpec *pspec)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (object);
-
-  switch (param_id) {
-  case PROP_HOOK_WIDGET:
-    empathy_live_search_set_hook_widget (self, g_value_get_object (value));
-    break;
-  case PROP_TEXT:
-    empathy_live_search_set_text (self, g_value_get_string (value));
-    break;
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-    break;
-  };
-}
-
-static void
-live_search_unmap (GtkWidget *widget)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (widget);
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  GTK_WIDGET_CLASS (empathy_live_search_parent_class)->unmap (widget);
-
-  /* unmap can happen if a parent gets hidden, in that case we want to hide
-   * the live search as well, so when it gets mapped again, the live search
-   * won't be shown. */
-  gtk_widget_hide (widget);
-
-  gtk_entry_set_text (GTK_ENTRY (priv->search_entry), "");
-
-  if (priv->hook_widget != NULL)
-    gtk_widget_grab_focus (priv->hook_widget);
-}
-
-static void
-live_search_show (GtkWidget *widget)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (widget);
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  if (!gtk_widget_has_focus (priv->search_entry))
-    gtk_widget_grab_focus (priv->search_entry);
-
-  GTK_WIDGET_CLASS (empathy_live_search_parent_class)->show (widget);
-}
-
-static void
-live_search_grab_focus (GtkWidget *widget)
-{
-  EmpathyLiveSearch *self = EMPATHY_LIVE_SEARCH (widget);
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  if (!gtk_widget_has_focus (priv->search_entry))
-    {
-      gtk_widget_grab_focus (priv->search_entry);
-      gtk_editable_set_position (GTK_EDITABLE (priv->search_entry), -1);
-    }
-}
-
-static void
-empathy_live_search_class_init (EmpathyLiveSearchClass *klass)
-{
-  GObjectClass *object_class = (GObjectClass *) klass;
-  GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
-  GParamSpec *param_spec;
-
-  object_class->finalize = live_search_finalize;
-  object_class->dispose = live_search_dispose;
-  object_class->get_property = live_search_get_property;
-  object_class->set_property = live_search_set_property;
-
-  widget_class->unmap = live_search_unmap;
-  widget_class->show = live_search_show;
-  widget_class->grab_focus = live_search_grab_focus;
-
-  signals[ACTIVATE] = g_signal_new ("activate",
-      G_TYPE_FROM_CLASS (object_class),
-      G_SIGNAL_RUN_LAST,
-      0,
-      NULL, NULL,
-      g_cclosure_marshal_generic,
-      G_TYPE_NONE, 0);
-
-  signals[KEYNAV] = g_signal_new ("key-navigation",
-      G_TYPE_FROM_CLASS (object_class),
-      G_SIGNAL_RUN_LAST,
-      0,
-      g_signal_accumulator_true_handled, NULL,
-      g_cclosure_marshal_generic,
-      G_TYPE_BOOLEAN, 1, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
-
-  param_spec = g_param_spec_object ("hook-widget", "Live Search Hook Widget",
-      "The live search catches key-press-events on this widget",
-      GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-  g_object_class_install_property (object_class, PROP_HOOK_WIDGET,
-      param_spec);
-
-  param_spec = g_param_spec_string ("text", "Live Search Text",
-      "The text of the live search entry",
-      "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-  g_object_class_install_property (object_class, PROP_TEXT, param_spec);
-
-  g_type_class_add_private (klass, sizeof (EmpathyLiveSearchPriv));
-}
-
-static void
-empathy_live_search_init (EmpathyLiveSearch *self)
-{
-  EmpathyLiveSearchPriv *priv =
-    G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_LIVE_SEARCH,
-        EmpathyLiveSearchPriv);
-
-  gtk_widget_set_no_show_all (GTK_WIDGET (self), TRUE);
-
-  priv->search_entry = gtk_entry_new ();
-  gtk_entry_set_icon_from_stock (GTK_ENTRY (priv->search_entry),
-      GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLOSE);
-  gtk_entry_set_icon_activatable (GTK_ENTRY (priv->search_entry),
-      GTK_ENTRY_ICON_SECONDARY, TRUE);
-  gtk_entry_set_icon_sensitive (GTK_ENTRY (priv->search_entry),
-      GTK_ENTRY_ICON_SECONDARY, TRUE);
-  gtk_widget_show (priv->search_entry);
-
-  gtk_box_pack_start (GTK_BOX (self), priv->search_entry, TRUE, TRUE, 0);
-
-  g_signal_connect (priv->search_entry, "icon_release",
-      G_CALLBACK (live_search_close_pressed), self);
-  g_signal_connect (priv->search_entry, "changed",
-      G_CALLBACK (live_search_text_changed), self);
-  g_signal_connect (priv->search_entry, "key-press-event",
-      G_CALLBACK (live_search_entry_key_pressed_cb), self);
-  g_signal_connect (priv->search_entry, "activate",
-      G_CALLBACK (live_search_entry_activate_cb), self);
-
-  priv->hook_widget = NULL;
-
-  self->priv = priv;
-}
-
-GtkWidget *
-empathy_live_search_new (GtkWidget *hook)
-{
-  g_return_val_if_fail (hook == NULL || GTK_IS_WIDGET (hook), NULL);
-
-  return g_object_new (EMPATHY_TYPE_LIVE_SEARCH,
-      "hook-widget", hook,
-      NULL);
-}
-
-/* public methods */
-
-GtkWidget *
-empathy_live_search_get_hook_widget (EmpathyLiveSearch *self)
-{
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  g_return_val_if_fail (EMPATHY_IS_LIVE_SEARCH (self), NULL);
-
-  return priv->hook_widget;
-}
-
-void
-empathy_live_search_set_hook_widget (EmpathyLiveSearch *self,
-    GtkWidget *hook)
-{
-  EmpathyLiveSearchPriv *priv;
-
-  g_return_if_fail (EMPATHY_IS_LIVE_SEARCH (self));
-  g_return_if_fail (hook == NULL || GTK_IS_WIDGET (hook));
-
-  priv = GET_PRIV (self);
-
-  /* release the actual widget */
-  live_search_release_hook_widget (self);
-
-  /* connect handlers if new source is not null */
-  if (hook != NULL)
-    {
-      priv->hook_widget = g_object_ref (hook);
-      g_signal_connect (priv->hook_widget, "key-press-event",
-          G_CALLBACK (live_search_key_press_event_cb),
-          self);
-      g_signal_connect (priv->hook_widget, "destroy",
-          G_CALLBACK (live_search_hook_widget_destroy_cb),
-          self);
-    }
-}
-
-const gchar *
-empathy_live_search_get_text (EmpathyLiveSearch *self)
-{
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  g_return_val_if_fail (EMPATHY_IS_LIVE_SEARCH (self), NULL);
-
-  return gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
-}
-
-void
-empathy_live_search_set_text (EmpathyLiveSearch *self,
-    const gchar *text)
-{
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  g_return_if_fail (EMPATHY_IS_LIVE_SEARCH (self));
-  g_return_if_fail (text != NULL);
-
-  gtk_entry_set_text (GTK_ENTRY (priv->search_entry), text);
-}
-
-/**
- * empathy_live_search_match:
- * @self: a #EmpathyLiveSearch
- * @string: a string where to search, must be valid UTF-8.
- *
- * Search if one of the words in @string string starts with the current text
- * of @self.
- *
- * Searching for "aba" in "Abasto" will match, searching in "Moraba" will not,
- * and searching in "A tool (abacus)" will do.
- *
- * The match is not case-sensitive, and regardless of the accentuation marks.
- *
- * Returns: %TRUE if a match is found, %FALSE otherwise.
- *
- **/
-gboolean
-empathy_live_search_match (EmpathyLiveSearch *self,
-    const gchar *string)
-{
-  EmpathyLiveSearchPriv *priv;
-
-  g_return_val_if_fail (EMPATHY_IS_LIVE_SEARCH (self), FALSE);
-
-  priv = GET_PRIV (self);
-
-  return empathy_live_search_match_words (string, priv->stripped_words);
-}
-
-gboolean
-empathy_live_search_match_string (const gchar *string,
-    const gchar *prefix)
-{
-  GPtrArray *words;
-  gboolean match;
-
-  words = empathy_live_search_strip_utf8_string (prefix);
-  match = empathy_live_search_match_words (string, words);
-  if (words != NULL)
-    g_ptr_array_unref (words);
-
-  return match;
-}
-
-GPtrArray *
-empathy_live_search_get_words (EmpathyLiveSearch *self)
-{
-  EmpathyLiveSearchPriv *priv = GET_PRIV (self);
-
-  return priv->stripped_words;
-}
diff --git a/libempathy-gtk/empathy-live-search.h b/libempathy-gtk/empathy-live-search.h
deleted file mode 100644 (file)
index 3d0a873..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2010 Collabora Ltd.
- * Copyright (C) 2007-2010 Nokia Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * Authors: Felix Kaser <felix.kaser@collabora.co.uk>
- *          Xavier Claessens <xavier.claessens@collabora.co.uk>
- *          Claudio Saavedra <csaavedra@igalia.com>
- */
-
-#ifndef __EMPATHY_LIVE_SEARCH_H__
-#define __EMPATHY_LIVE_SEARCH_H__
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define EMPATHY_TYPE_LIVE_SEARCH         (empathy_live_search_get_type ())
-#define EMPATHY_LIVE_SEARCH(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_LIVE_SEARCH, EmpathyLiveSearch))
-#define EMPATHY_LIVE_SEARCH_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_LIVE_SEARCH, EmpathyLiveSearchClass))
-#define EMPATHY_IS_LIVE_SEARCH(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_LIVE_SEARCH))
-#define EMPATHY_IS_LIVE_SEARCH_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_LIVE_SEARCH))
-#define EMPATHY_LIVE_SEARCH_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_LIVE_SEARCH, EmpathyLiveSearchClass))
-
-typedef struct _EmpathyLiveSearch      EmpathyLiveSearch;
-typedef struct _EmpathyLiveSearchClass EmpathyLiveSearchClass;
-
-struct _EmpathyLiveSearch {
-  GtkHBox parent;
-
-  /*<private>*/
-  gpointer priv;
-};
-
-struct _EmpathyLiveSearchClass {
-  GtkHBoxClass parent_class;
-};
-
-GType empathy_live_search_get_type (void) G_GNUC_CONST;
-GtkWidget *empathy_live_search_new (GtkWidget *hook);
-
-GtkWidget *empathy_live_search_get_hook_widget (EmpathyLiveSearch *self);
-void empathy_live_search_set_hook_widget (EmpathyLiveSearch *self,
-    GtkWidget *hook);
-
-const gchar *empathy_live_search_get_text (EmpathyLiveSearch *self);
-void empathy_live_search_set_text (EmpathyLiveSearch *self,
-    const gchar *text);
-
-gboolean empathy_live_search_match (EmpathyLiveSearch *self,
-    const gchar *string);
-
-GPtrArray * empathy_live_search_strip_utf8_string (const gchar *string);
-
-gboolean empathy_live_search_match_words (const gchar *string,
-    GPtrArray *words);
-
-GPtrArray * empathy_live_search_get_words (EmpathyLiveSearch *self);
-
-/* Made public for unit tests */
-gboolean empathy_live_search_match_string (const gchar *string,
-   const gchar *prefix);
-
-G_END_DECLS
-
-#endif /* __EMPATHY_LIVE_SEARCH_H__ */
index a6b6ffe5caaa6e8b446d186088e3800a01eef5b9..441351066fc05dbd13f81097ad55a97ed41107f9 100644 (file)
@@ -67,7 +67,7 @@ struct _EmpathyRosterViewPriv
   gboolean show_groups;
   gboolean empty;
 
-  EmpathyLiveSearch *search;
+  TpawLiveSearch *search;
 
   EmpathyRosterModel *model;
 };
@@ -864,8 +864,8 @@ contact_should_be_displayed (EmpathyRosterView *self,
       individual = empathy_roster_contact_get_individual (contact);
 
       return empathy_individual_match_string (individual,
-          empathy_live_search_get_text (self->priv->search),
-          empathy_live_search_get_words (self->priv->search));
+          tpaw_live_search_get_text (self->priv->search),
+          tpaw_live_search_get_words (self->priv->search));
     }
 
   if (self->priv->show_offline)
@@ -1473,7 +1473,7 @@ search_timeout_cb (EmpathyRosterView *self)
 }
 
 static void
-search_text_notify_cb (EmpathyLiveSearch *search,
+search_text_notify_cb (TpawLiveSearch *search,
     GParamSpec *pspec,
     EmpathyRosterView *self)
 {
@@ -1500,7 +1500,7 @@ search_activate_cb (GtkWidget *search,
 
 void
 empathy_roster_view_set_live_search (EmpathyRosterView *self,
-    EmpathyLiveSearch *search)
+    TpawLiveSearch *search)
 {
   if (self->priv->search != NULL)
     {
index c09d09c3a7c770e103e9efda53925e8cea644851..586d75b86f3859326b25e6c004ab98015af74c9f 100644 (file)
@@ -2,8 +2,9 @@
 #ifndef __EMPATHY_ROSTER_VIEW_H__
 #define __EMPATHY_ROSTER_VIEW_H__
 
+#include <tp-account-widgets/tpaw-live-search.h>
+
 #include "egg-list-box/egg-list-box.h"
-#include "empathy-live-search.h"
 #include "empathy-roster-model.h"
 
 G_BEGIN_DECLS
@@ -58,7 +59,7 @@ void empathy_roster_view_show_groups (EmpathyRosterView *self,
     gboolean show);
 
 void empathy_roster_view_set_live_search (EmpathyRosterView *self,
-    EmpathyLiveSearch *search);
+    TpawLiveSearch *search);
 
 gboolean empathy_roster_view_is_empty (EmpathyRosterView *self);
 
index 86edb3b0a158cdc2a98a7363cd7ac223e875b067..ec868a39f3aeebbfbb1a0af20ff449627285bb1e 100644 (file)
 #include <gdk/gdkx.h>
 #include <glib/gi18n-lib.h>
 #include <gio/gdesktopappinfo.h>
+#include <tp-account-widgets/tpaw-live-search.h>
 
 #include "empathy-ft-factory.h"
 #include "empathy-images.h"
-#include "empathy-live-search.h"
 #include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
@@ -1406,7 +1406,7 @@ empathy_get_current_action_time (void)
   return (tp_user_action_time_from_x11 (gtk_get_current_event_time ()));
 }
 
-/* @words = empathy_live_search_strip_utf8_string (@text);
+/* @words = tpaw_live_search_strip_utf8_string (@text);
  *
  * User has to pass both so we don't have to compute @words ourself each time
  * this function is called. */
@@ -1423,7 +1423,7 @@ empathy_individual_match_string (FolksIndividual *individual,
   /* check alias name */
   str = folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (individual));
 
-  if (empathy_live_search_match_words (str, words))
+  if (tpaw_live_search_match_words (str, words))
     return TRUE;
 
   personas = folks_individual_get_personas (individual);
@@ -1454,7 +1454,7 @@ empathy_individual_match_string (FolksIndividual *individual,
               if (p != NULL)
                 str = dup_str = g_strndup (str, p - str);
 
-              visible = empathy_live_search_match_words (str, words);
+              visible = tpaw_live_search_match_words (str, words);
               g_free (dup_str);
               if (visible)
                 retval = TRUE;
index 0fb2d83a72718de3e9c144bc1226f0e52462a904..1a30f7117d49ec2da76185f8da600d51c92552a8 100644 (file)
@@ -2371,10 +2371,10 @@ empathy_roster_window_init (EmpathyRosterWindow *self)
   gtk_widget_set_has_tooltip (GTK_WIDGET (self->priv->view), TRUE);
 
   /* Set up search bar */
-  self->priv->search_bar = empathy_live_search_new (
+  self->priv->search_bar = tpaw_live_search_new (
       GTK_WIDGET (self->priv->view));
   empathy_roster_view_set_live_search (self->priv->view,
-      EMPATHY_LIVE_SEARCH (self->priv->search_bar));
+      TPAW_LIVE_SEARCH (self->priv->search_bar));
   gtk_box_pack_start (GTK_BOX (search_vbox), self->priv->search_bar,
       FALSE, TRUE, 0);
 
index 10f0346f32db591bedd1c387319d2cf91de643be..2fb3e48db68adddcb4ca816456f0e21bd42d637c 100644 (file)
@@ -3,8 +3,8 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <tp-account-widgets/tpaw-live-search.h>
 
-#include "empathy-live-search.h"
 #include "test-helper.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_TESTS
@@ -57,7 +57,7 @@ test_live_search (void)
       gboolean match;
       gboolean ok;
 
-      match = empathy_live_search_match_string (tests[i].string, tests[i].prefix);
+      match = tpaw_live_search_match_string (tests[i].string, tests[i].prefix);
       ok = (match == tests[i].should_match);
 
       DEBUG ("'%s' - '%s' %s: %s", tests[i].string, tests[i].prefix,
index 397536b3a3b59eeb15d4e51d20d3f48acdcce0f1..86d8fe1c3b2684f892ec2b61156fd1aa9b7a6dac 100644 (file)
@@ -9,6 +9,7 @@ AM_CPPFLAGS =                                           \
        $(DISABLE_DEPRECATED)
 
 LDADD =                                                                \
+       $(top_builddir)/tp-account-widgets/libtp-account-widgets.la     \
        $(top_builddir)/libempathy-gtk/libempathy-gtk.la        \
        $(top_builddir)/libempathy/libempathy.la                \
        $(EMPATHY_LIBS)
index 74bb59f1797ecebaee28c9bc3001f0bf0ea44a1c..5d2dfdc559ff4a3737017fc077c3a1ca9e39cecc 100644 (file)
@@ -93,9 +93,9 @@ create_view_box (EmpathyRosterModel *model,
   empathy_roster_view_show_offline (EMPATHY_ROSTER_VIEW (view), show_offline);
   empathy_roster_view_show_groups (EMPATHY_ROSTER_VIEW (view), show_groups);
 
-  search = empathy_live_search_new (view);
+  search = tpaw_live_search_new (view);
   empathy_roster_view_set_live_search (EMPATHY_ROSTER_VIEW (view),
-      EMPATHY_LIVE_SEARCH (search));
+      TPAW_LIVE_SEARCH (search));
 
   scrolled = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
index 478b4e6cc537e0105bafd388206d1df751b774fd..b55843158643123ba62c501d5e17b43c93413291 100644 (file)
@@ -136,9 +136,9 @@ main (int argc,
   empathy_roster_view_show_offline (EMPATHY_ROSTER_VIEW (view), show_offline);
   empathy_roster_view_show_groups (EMPATHY_ROSTER_VIEW (view), show_groups);
 
-  search = empathy_live_search_new (view);
+  search = tpaw_live_search_new (view);
   empathy_roster_view_set_live_search (EMPATHY_ROSTER_VIEW (view),
-      EMPATHY_LIVE_SEARCH (search));
+      TPAW_LIVE_SEARCH (search));
 
   scrolled = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
index f814d9658322389331ebb6d6043f8abfbaa0cfc0..eb5cf6c6b8e88455d85e2706e7e922501f91b836 100644 (file)
@@ -128,9 +128,9 @@ main (int argc,
 
   g_object_unref (mgr);
 
-  search = empathy_live_search_new (view);
+  search = tpaw_live_search_new (view);
   empathy_roster_view_set_live_search (EMPATHY_ROSTER_VIEW (view),
-      EMPATHY_LIVE_SEARCH (search));
+      TPAW_LIVE_SEARCH (search));
 
   scrolled = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
index 29a8ed72d645954274fa8101b4b12ffce1654a0e..3ff553153cb9c05ff2b8e5617f37a4f53a71b10f 100644 (file)
@@ -29,6 +29,7 @@ libtp_account_widgets_sources =               \
        tpaw-irc-network-manager.c              \
        tpaw-irc-network.c                      \
        tpaw-irc-server.c                       \
+       tpaw-live-search.c                      \
        tpaw-utils.c                            \
        totem-subtitle-encoding.c               \
        $(NULL)
@@ -46,6 +47,7 @@ libtp_account_widgets_headers =                       \
        tpaw-irc-network-manager.h              \
        tpaw-irc-network.h                      \
        tpaw-irc-server.h                       \
+       tpaw-live-search.h                      \
        tpaw-utils.h                            \
        totem-subtitle-encoding.h               \
        $(NULL)
index c7995a56ff538d9ad2b416cd0546311aca35e137..daf35a0f07482abfbd05dc03f108560dd5676193 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "tpaw-irc-network-dialog.h"
 #include "tpaw-irc-network-manager.h"
-#include "empathy-live-search.h"
+#include "tpaw-live-search.h"
 #include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT | EMPATHY_DEBUG_IRC
@@ -436,7 +436,7 @@ filter_visible_func (GtkTreeModel *model,
 
   gtk_tree_model_get (model, iter, COL_NETWORK_OBJ, &network, -1);
 
-  visible = empathy_live_search_match (EMPATHY_LIVE_SEARCH (priv->search),
+  visible = tpaw_live_search_match (TPAW_LIVE_SEARCH (priv->search),
       tpaw_irc_network_get_name (network));
 
   g_object_unref (network);
@@ -452,7 +452,7 @@ search_activate_cb (GtkWidget *search,
 }
 
 static void
-search_text_notify_cb (EmpathyLiveSearch *search,
+search_text_notify_cb (TpawLiveSearch *search,
     GParamSpec *pspec,
     TpawIrcNetworkChooserDialog *self)
 {
@@ -468,7 +468,7 @@ search_text_notify_cb (EmpathyLiveSearch *search,
     {
       const gchar *text;
 
-      text = empathy_live_search_get_text (EMPATHY_LIVE_SEARCH (priv->search));
+      text = tpaw_live_search_get_text (TPAW_LIVE_SEARCH (priv->search));
       if (!EMP_STR_EMPTY (text))
         {
           /* We are doing a search, select the first matching network */
@@ -592,7 +592,7 @@ tpaw_irc_network_chooser_dialog_constructed (GObject *object)
   gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
   /* Live search */
-  priv->search = empathy_live_search_new (priv->treeview);
+  priv->search = tpaw_live_search_new (priv->treeview);
 
   gtk_box_pack_start (GTK_BOX (vbox), priv->search, FALSE, TRUE, 0);
 
@@ -653,7 +653,7 @@ tpaw_irc_network_chooser_dialog_dispose (GObject *object)
 
   if (priv->search != NULL)
     {
-      empathy_live_search_set_hook_widget (EMPATHY_LIVE_SEARCH (priv->search),
+      tpaw_live_search_set_hook_widget (TPAW_LIVE_SEARCH (priv->search),
           NULL);
 
       priv->search = NULL;
diff --git a/tp-account-widgets/tpaw-live-search.c b/tp-account-widgets/tpaw-live-search.c
new file mode 100644 (file)
index 0000000..1547a4b
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2007-2010 Nokia Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors: Felix Kaser <felix.kaser@collabora.co.uk>
+ *          Xavier Claessens <xavier.claessens@collabora.co.uk>
+ *          Claudio Saavedra <csaavedra@igalia.com>
+ */
+
+#include "config.h"
+#include "tpaw-live-search.h"
+
+#include "empathy-utils.h"
+
+G_DEFINE_TYPE (TpawLiveSearch, tpaw_live_search, GTK_TYPE_HBOX)
+
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, TpawLiveSearch)
+
+typedef struct
+{
+  GtkWidget *search_entry;
+  GtkWidget *hook_widget;
+
+  GPtrArray *stripped_words;
+} TpawLiveSearchPriv;
+
+enum
+{
+  PROP_0,
+  PROP_HOOK_WIDGET,
+  PROP_TEXT
+};
+
+enum
+{
+  ACTIVATE,
+  KEYNAV,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void live_search_hook_widget_destroy_cb (GtkWidget *object,
+    gpointer user_data);
+
+/**
+ * stripped_char:
+ *
+ * Returns a stripped version of @ch, removing any case, accentuation
+ * mark, or any special mark on it.
+ **/
+static gunichar
+stripped_char (gunichar ch)
+{
+  gunichar retval = 0;
+  GUnicodeType utype;
+
+  utype = g_unichar_type (ch);
+
+  switch (utype)
+    {
+    case G_UNICODE_CONTROL:
+    case G_UNICODE_FORMAT:
+    case G_UNICODE_UNASSIGNED:
+    case G_UNICODE_NON_SPACING_MARK:
+    case G_UNICODE_COMBINING_MARK:
+    case G_UNICODE_ENCLOSING_MARK:
+      /* Ignore those */
+      break;
+    case G_UNICODE_PRIVATE_USE:
+    case G_UNICODE_SURROGATE:
+    case G_UNICODE_LOWERCASE_LETTER:
+    case G_UNICODE_MODIFIER_LETTER:
+    case G_UNICODE_OTHER_LETTER:
+    case G_UNICODE_TITLECASE_LETTER:
+    case G_UNICODE_UPPERCASE_LETTER:
+    case G_UNICODE_DECIMAL_NUMBER:
+    case G_UNICODE_LETTER_NUMBER:
+    case G_UNICODE_OTHER_NUMBER:
+    case G_UNICODE_CONNECT_PUNCTUATION:
+    case G_UNICODE_DASH_PUNCTUATION:
+    case G_UNICODE_CLOSE_PUNCTUATION:
+    case G_UNICODE_FINAL_PUNCTUATION:
+    case G_UNICODE_INITIAL_PUNCTUATION:
+    case G_UNICODE_OTHER_PUNCTUATION:
+    case G_UNICODE_OPEN_PUNCTUATION:
+    case G_UNICODE_CURRENCY_SYMBOL:
+    case G_UNICODE_MODIFIER_SYMBOL:
+    case G_UNICODE_MATH_SYMBOL:
+    case G_UNICODE_OTHER_SYMBOL:
+    case G_UNICODE_LINE_SEPARATOR:
+    case G_UNICODE_PARAGRAPH_SEPARATOR:
+    case G_UNICODE_SPACE_SEPARATOR:
+    default:
+      ch = g_unichar_tolower (ch);
+      g_unichar_fully_decompose (ch, FALSE, &retval, 1);
+    }
+
+  return retval;
+}
+
+static void
+append_word (GPtrArray **word_array,
+    GString **word)
+{
+  if (*word != NULL)
+    {
+      if (*word_array == NULL)
+        *word_array = g_ptr_array_new_with_free_func (g_free);
+      g_ptr_array_add (*word_array, g_string_free (*word, FALSE));
+      *word = NULL;
+    }
+}
+
+GPtrArray *
+tpaw_live_search_strip_utf8_string (const gchar *string)
+{
+  GPtrArray *word_array = NULL;
+  GString *word = NULL;
+  const gchar *p;
+
+  if (EMP_STR_EMPTY (string))
+    return NULL;
+
+  for (p = string; *p != '\0'; p = g_utf8_next_char (p))
+    {
+      gunichar sc;
+
+      /* Make the char lower-case, remove its accentuation marks, and ignore it
+       * if it is just unicode marks */
+      sc = stripped_char (g_utf8_get_char (p));
+      if (sc == 0)
+        continue;
+
+      /* If it is not alpha-num, it is separator between words */
+      if (!g_unichar_isalnum (sc))
+        {
+          append_word (&word_array, &word);
+          continue;
+        }
+
+      /* It is alpha-num, append this char to current word, or start new word */
+      if (word == NULL)
+        word = g_string_new (NULL);
+      g_string_append_unichar (word, sc);
+    }
+
+  append_word (&word_array, &word);
+
+  return word_array;
+}
+
+static gboolean
+live_search_match_prefix (const gchar *string,
+    const gchar *prefix)
+{
+  const gchar *p;
+  const gchar *prefix_p;
+  gboolean next_word = FALSE;
+
+  if (prefix == NULL || prefix[0] == 0)
+    return TRUE;
+
+  if (EMP_STR_EMPTY (string))
+    return FALSE;
+
+  prefix_p = prefix;
+  for (p = string; *p != '\0'; p = g_utf8_next_char (p))
+    {
+      gunichar sc;
+
+      /* Make the char lower-case, remove its accentuation marks, and ignore it
+       * if it is just unicode marks */
+      sc = stripped_char (g_utf8_get_char (p));
+      if (sc == 0)
+        continue;
+
+      /* If we want to go to next word, ignore alpha-num chars */
+      if (next_word && g_unichar_isalnum (sc))
+        continue;
+      next_word = FALSE;
+
+      /* Ignore word separators */
+      if (!g_unichar_isalnum (sc))
+        continue;
+
+      /* If this char does not match prefix_p, go to next word and start again
+       * from the beginning of prefix */
+      if (sc != g_utf8_get_char (prefix_p))
+        {
+          next_word = TRUE;
+          prefix_p = prefix;
+          continue;
+        }
+
+      /* prefix_p match, verify to next char. If this was the last of prefix,
+       * it means it completely machted and we are done. */
+      prefix_p = g_utf8_next_char (prefix_p);
+      if (*prefix_p == '\0')
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+gboolean
+tpaw_live_search_match_words (const gchar *string,
+    GPtrArray *words)
+{
+  guint i;
+
+  if (words == NULL)
+    return TRUE;
+
+  for (i = 0; i < words->len; i++)
+    if (!live_search_match_prefix (string, g_ptr_array_index (words, i)))
+      return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+fire_key_navigation_sig (TpawLiveSearch *self,
+    GdkEventKey *event)
+{
+  gboolean ret;
+
+  g_signal_emit (self, signals[KEYNAV], 0, event, &ret);
+  return ret;
+}
+
+static gboolean
+live_search_entry_key_pressed_cb (GtkEntry *entry,
+    GdkEventKey *event,
+    gpointer user_data)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (user_data);
+
+  /* if esc key pressed, hide the search */
+  if (event->keyval == GDK_KEY_Escape)
+    {
+      gtk_widget_hide (GTK_WIDGET (self));
+      return TRUE;
+    }
+
+  /* emit key navigation signal, so other widgets can respond to it properly */
+  if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down
+      || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down
+      || event->keyval == GDK_KEY_Menu)
+     {
+       return fire_key_navigation_sig (self, event);
+     }
+
+  if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End ||
+      event->keyval == GDK_KEY_space)
+    {
+      /* If the live search is visible, the entry should catch the Home/End
+       * and space events */
+      if (!gtk_widget_get_visible (GTK_WIDGET (self)))
+        {
+          return fire_key_navigation_sig (self, event);
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+live_search_text_changed (GtkEntry *entry,
+    gpointer user_data)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (user_data);
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+  const gchar *text;
+
+  text = gtk_entry_get_text (entry);
+
+  if (EMP_STR_EMPTY (text))
+    gtk_widget_hide (GTK_WIDGET (self));
+  else
+    gtk_widget_show (GTK_WIDGET (self));
+
+  if (priv->stripped_words != NULL)
+    g_ptr_array_unref (priv->stripped_words);
+
+  priv->stripped_words = tpaw_live_search_strip_utf8_string (text);
+
+  g_object_notify (G_OBJECT (self), "text");
+}
+
+static void
+live_search_close_pressed (GtkEntry *entry,
+    GtkEntryIconPosition icon_pos,
+    GdkEvent *event,
+    gpointer user_data)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (user_data);
+
+  gtk_widget_hide (GTK_WIDGET (self));
+}
+
+static gboolean
+live_search_key_press_event_cb (GtkWidget *widget,
+    GdkEventKey *event,
+    gpointer user_data)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (user_data);
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+  GdkEvent *new_event;
+  gboolean ret;
+
+  /* dont forward this event to the entry, else the event is consumed by the
+   * entry and does not close the window */
+  if (!gtk_widget_get_visible (GTK_WIDGET (self)) &&
+      event->keyval == GDK_KEY_Escape)
+    return FALSE;
+
+  /* do not show the search if CTRL and/or ALT are pressed with a key
+   * this is needed, because otherwise the CTRL + F accel would not work,
+   * because the entry consumes it */
+  if (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK) ||
+      event->keyval == GDK_KEY_Control_L ||
+      event->keyval == GDK_KEY_Control_R)
+    return FALSE;
+
+  /* dont forward the up/down and Page Up/Down arrow keys to the entry,
+   * they are needed for navigation in the treeview and are not needed in
+   * the search entry */
+   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down ||
+       event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down ||
+       event->keyval == GDK_KEY_Menu)
+     return FALSE;
+
+   if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End ||
+       event->keyval == GDK_KEY_space)
+     {
+       /* Home/End and space keys have to be forwarded to the entry only if
+        * the live search is visible (to move the cursor inside the entry). */
+       if (!gtk_widget_get_visible (GTK_WIDGET (self)))
+         return FALSE;
+     }
+
+   /* Don't forward shift keys events as focusing the search entry would
+    * cancel an in-progress editing on a cell renderer (like when renaming a
+    * group). There is no point focusing it anyway as we don't display the
+    * search entry when only a shift key is pressed. */
+   if (event->keyval == GDK_KEY_Shift_L ||
+       event->keyval == GDK_KEY_Shift_R)
+       return FALSE;
+
+  /* realize the widget if it is not realized yet */
+  gtk_widget_realize (priv->search_entry);
+  if (!gtk_widget_has_focus (priv->search_entry))
+    {
+      gtk_widget_grab_focus (priv->search_entry);
+      gtk_editable_set_position (GTK_EDITABLE (priv->search_entry), -1);
+    }
+
+  /* forward the event to the search entry */
+  new_event = gdk_event_copy ((GdkEvent *) event);
+  ret = gtk_widget_event (priv->search_entry, new_event);
+  gdk_event_free (new_event);
+
+  return ret;
+}
+
+static void
+live_search_entry_activate_cb (GtkEntry *entry,
+    TpawLiveSearch *self)
+{
+  g_signal_emit (self, signals[ACTIVATE], 0);
+}
+
+static void
+live_search_release_hook_widget (TpawLiveSearch *self)
+{
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  /* remove old handlers if old source was not null */
+  if (priv->hook_widget != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (priv->hook_widget,
+          live_search_key_press_event_cb, self);
+      g_signal_handlers_disconnect_by_func (priv->hook_widget,
+          live_search_hook_widget_destroy_cb, self);
+      g_object_unref (priv->hook_widget);
+      priv->hook_widget = NULL;
+    }
+}
+
+static void
+live_search_hook_widget_destroy_cb (GtkWidget *object,
+    gpointer user_data)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (user_data);
+
+  /* unref the hook widget and hide search */
+  gtk_widget_hide (GTK_WIDGET (self));
+  live_search_release_hook_widget (self);
+}
+
+static void
+live_search_dispose (GObject *obj)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (obj);
+
+  live_search_release_hook_widget (self);
+
+  if (G_OBJECT_CLASS (tpaw_live_search_parent_class)->dispose != NULL)
+    G_OBJECT_CLASS (tpaw_live_search_parent_class)->dispose (obj);
+}
+
+static void
+live_search_finalize (GObject *obj)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (obj);
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  if (priv->stripped_words != NULL)
+    g_ptr_array_unref (priv->stripped_words);
+
+  if (G_OBJECT_CLASS (tpaw_live_search_parent_class)->finalize != NULL)
+    G_OBJECT_CLASS (tpaw_live_search_parent_class)->finalize (obj);
+}
+
+static void
+live_search_get_property (GObject *object,
+    guint param_id,
+    GValue *value,
+    GParamSpec *pspec)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (object);
+
+  switch (param_id)
+    {
+    case PROP_HOOK_WIDGET:
+      g_value_set_object (value, tpaw_live_search_get_hook_widget (self));
+      break;
+    case PROP_TEXT:
+      g_value_set_string (value, tpaw_live_search_get_text (self));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+    }
+}
+
+static void
+live_search_set_property (GObject *object,
+    guint param_id,
+    const GValue *value,
+    GParamSpec *pspec)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (object);
+
+  switch (param_id) {
+  case PROP_HOOK_WIDGET:
+    tpaw_live_search_set_hook_widget (self, g_value_get_object (value));
+    break;
+  case PROP_TEXT:
+    tpaw_live_search_set_text (self, g_value_get_string (value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+    break;
+  };
+}
+
+static void
+live_search_unmap (GtkWidget *widget)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (widget);
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  GTK_WIDGET_CLASS (tpaw_live_search_parent_class)->unmap (widget);
+
+  /* unmap can happen if a parent gets hidden, in that case we want to hide
+   * the live search as well, so when it gets mapped again, the live search
+   * won't be shown. */
+  gtk_widget_hide (widget);
+
+  gtk_entry_set_text (GTK_ENTRY (priv->search_entry), "");
+
+  if (priv->hook_widget != NULL)
+    gtk_widget_grab_focus (priv->hook_widget);
+}
+
+static void
+live_search_show (GtkWidget *widget)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (widget);
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  if (!gtk_widget_has_focus (priv->search_entry))
+    gtk_widget_grab_focus (priv->search_entry);
+
+  GTK_WIDGET_CLASS (tpaw_live_search_parent_class)->show (widget);
+}
+
+static void
+live_search_grab_focus (GtkWidget *widget)
+{
+  TpawLiveSearch *self = TPAW_LIVE_SEARCH (widget);
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  if (!gtk_widget_has_focus (priv->search_entry))
+    {
+      gtk_widget_grab_focus (priv->search_entry);
+      gtk_editable_set_position (GTK_EDITABLE (priv->search_entry), -1);
+    }
+}
+
+static void
+tpaw_live_search_class_init (TpawLiveSearchClass *klass)
+{
+  GObjectClass *object_class = (GObjectClass *) klass;
+  GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
+  GParamSpec *param_spec;
+
+  object_class->finalize = live_search_finalize;
+  object_class->dispose = live_search_dispose;
+  object_class->get_property = live_search_get_property;
+  object_class->set_property = live_search_set_property;
+
+  widget_class->unmap = live_search_unmap;
+  widget_class->show = live_search_show;
+  widget_class->grab_focus = live_search_grab_focus;
+
+  signals[ACTIVATE] = g_signal_new ("activate",
+      G_TYPE_FROM_CLASS (object_class),
+      G_SIGNAL_RUN_LAST,
+      0,
+      NULL, NULL,
+      g_cclosure_marshal_generic,
+      G_TYPE_NONE, 0);
+
+  signals[KEYNAV] = g_signal_new ("key-navigation",
+      G_TYPE_FROM_CLASS (object_class),
+      G_SIGNAL_RUN_LAST,
+      0,
+      g_signal_accumulator_true_handled, NULL,
+      g_cclosure_marshal_generic,
+      G_TYPE_BOOLEAN, 1, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+  param_spec = g_param_spec_object ("hook-widget", "Live Search Hook Widget",
+      "The live search catches key-press-events on this widget",
+      GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_HOOK_WIDGET,
+      param_spec);
+
+  param_spec = g_param_spec_string ("text", "Live Search Text",
+      "The text of the live search entry",
+      "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_TEXT, param_spec);
+
+  g_type_class_add_private (klass, sizeof (TpawLiveSearchPriv));
+}
+
+static void
+tpaw_live_search_init (TpawLiveSearch *self)
+{
+  TpawLiveSearchPriv *priv =
+    G_TYPE_INSTANCE_GET_PRIVATE ((self), TPAW_TYPE_LIVE_SEARCH,
+        TpawLiveSearchPriv);
+
+  gtk_widget_set_no_show_all (GTK_WIDGET (self), TRUE);
+
+  priv->search_entry = gtk_entry_new ();
+  gtk_entry_set_icon_from_stock (GTK_ENTRY (priv->search_entry),
+      GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLOSE);
+  gtk_entry_set_icon_activatable (GTK_ENTRY (priv->search_entry),
+      GTK_ENTRY_ICON_SECONDARY, TRUE);
+  gtk_entry_set_icon_sensitive (GTK_ENTRY (priv->search_entry),
+      GTK_ENTRY_ICON_SECONDARY, TRUE);
+  gtk_widget_show (priv->search_entry);
+
+  gtk_box_pack_start (GTK_BOX (self), priv->search_entry, TRUE, TRUE, 0);
+
+  g_signal_connect (priv->search_entry, "icon_release",
+      G_CALLBACK (live_search_close_pressed), self);
+  g_signal_connect (priv->search_entry, "changed",
+      G_CALLBACK (live_search_text_changed), self);
+  g_signal_connect (priv->search_entry, "key-press-event",
+      G_CALLBACK (live_search_entry_key_pressed_cb), self);
+  g_signal_connect (priv->search_entry, "activate",
+      G_CALLBACK (live_search_entry_activate_cb), self);
+
+  priv->hook_widget = NULL;
+
+  self->priv = priv;
+}
+
+GtkWidget *
+tpaw_live_search_new (GtkWidget *hook)
+{
+  g_return_val_if_fail (hook == NULL || GTK_IS_WIDGET (hook), NULL);
+
+  return g_object_new (TPAW_TYPE_LIVE_SEARCH,
+      "hook-widget", hook,
+      NULL);
+}
+
+/* public methods */
+
+GtkWidget *
+tpaw_live_search_get_hook_widget (TpawLiveSearch *self)
+{
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  g_return_val_if_fail (TPAW_IS_LIVE_SEARCH (self), NULL);
+
+  return priv->hook_widget;
+}
+
+void
+tpaw_live_search_set_hook_widget (TpawLiveSearch *self,
+    GtkWidget *hook)
+{
+  TpawLiveSearchPriv *priv;
+
+  g_return_if_fail (TPAW_IS_LIVE_SEARCH (self));
+  g_return_if_fail (hook == NULL || GTK_IS_WIDGET (hook));
+
+  priv = GET_PRIV (self);
+
+  /* release the actual widget */
+  live_search_release_hook_widget (self);
+
+  /* connect handlers if new source is not null */
+  if (hook != NULL)
+    {
+      priv->hook_widget = g_object_ref (hook);
+      g_signal_connect (priv->hook_widget, "key-press-event",
+          G_CALLBACK (live_search_key_press_event_cb),
+          self);
+      g_signal_connect (priv->hook_widget, "destroy",
+          G_CALLBACK (live_search_hook_widget_destroy_cb),
+          self);
+    }
+}
+
+const gchar *
+tpaw_live_search_get_text (TpawLiveSearch *self)
+{
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  g_return_val_if_fail (TPAW_IS_LIVE_SEARCH (self), NULL);
+
+  return gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
+}
+
+void
+tpaw_live_search_set_text (TpawLiveSearch *self,
+    const gchar *text)
+{
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  g_return_if_fail (TPAW_IS_LIVE_SEARCH (self));
+  g_return_if_fail (text != NULL);
+
+  gtk_entry_set_text (GTK_ENTRY (priv->search_entry), text);
+}
+
+/**
+ * tpaw_live_search_match:
+ * @self: a #TpawLiveSearch
+ * @string: a string where to search, must be valid UTF-8.
+ *
+ * Search if one of the words in @string string starts with the current text
+ * of @self.
+ *
+ * Searching for "aba" in "Abasto" will match, searching in "Moraba" will not,
+ * and searching in "A tool (abacus)" will do.
+ *
+ * The match is not case-sensitive, and regardless of the accentuation marks.
+ *
+ * Returns: %TRUE if a match is found, %FALSE otherwise.
+ *
+ **/
+gboolean
+tpaw_live_search_match (TpawLiveSearch *self,
+    const gchar *string)
+{
+  TpawLiveSearchPriv *priv;
+
+  g_return_val_if_fail (TPAW_IS_LIVE_SEARCH (self), FALSE);
+
+  priv = GET_PRIV (self);
+
+  return tpaw_live_search_match_words (string, priv->stripped_words);
+}
+
+gboolean
+tpaw_live_search_match_string (const gchar *string,
+    const gchar *prefix)
+{
+  GPtrArray *words;
+  gboolean match;
+
+  words = tpaw_live_search_strip_utf8_string (prefix);
+  match = tpaw_live_search_match_words (string, words);
+  if (words != NULL)
+    g_ptr_array_unref (words);
+
+  return match;
+}
+
+GPtrArray *
+tpaw_live_search_get_words (TpawLiveSearch *self)
+{
+  TpawLiveSearchPriv *priv = GET_PRIV (self);
+
+  return priv->stripped_words;
+}
diff --git a/tp-account-widgets/tpaw-live-search.h b/tp-account-widgets/tpaw-live-search.h
new file mode 100644 (file)
index 0000000..50aad92
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2007-2010 Nokia Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors: Felix Kaser <felix.kaser@collabora.co.uk>
+ *          Xavier Claessens <xavier.claessens@collabora.co.uk>
+ *          Claudio Saavedra <csaavedra@igalia.com>
+ */
+
+#ifndef __TPAW_LIVE_SEARCH_H__
+#define __TPAW_LIVE_SEARCH_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define TPAW_TYPE_LIVE_SEARCH         (tpaw_live_search_get_type ())
+#define TPAW_LIVE_SEARCH(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TPAW_TYPE_LIVE_SEARCH, TpawLiveSearch))
+#define TPAW_LIVE_SEARCH_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), TPAW_TYPE_LIVE_SEARCH, TpawLiveSearchClass))
+#define TPAW_IS_LIVE_SEARCH(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TPAW_TYPE_LIVE_SEARCH))
+#define TPAW_IS_LIVE_SEARCH_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), TPAW_TYPE_LIVE_SEARCH))
+#define TPAW_LIVE_SEARCH_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TPAW_TYPE_LIVE_SEARCH, TpawLiveSearchClass))
+
+typedef struct _TpawLiveSearch      TpawLiveSearch;
+typedef struct _TpawLiveSearchClass TpawLiveSearchClass;
+
+struct _TpawLiveSearch {
+  GtkHBox parent;
+
+  /*<private>*/
+  gpointer priv;
+};
+
+struct _TpawLiveSearchClass {
+  GtkHBoxClass parent_class;
+};
+
+GType tpaw_live_search_get_type (void) G_GNUC_CONST;
+GtkWidget *tpaw_live_search_new (GtkWidget *hook);
+
+GtkWidget *tpaw_live_search_get_hook_widget (TpawLiveSearch *self);
+void tpaw_live_search_set_hook_widget (TpawLiveSearch *self,
+    GtkWidget *hook);
+
+const gchar *tpaw_live_search_get_text (TpawLiveSearch *self);
+void tpaw_live_search_set_text (TpawLiveSearch *self,
+    const gchar *text);
+
+gboolean tpaw_live_search_match (TpawLiveSearch *self,
+    const gchar *string);
+
+GPtrArray * tpaw_live_search_strip_utf8_string (const gchar *string);
+
+gboolean tpaw_live_search_match_words (const gchar *string,
+    GPtrArray *words);
+
+GPtrArray * tpaw_live_search_get_words (TpawLiveSearch *self);
+
+/* Made public for unit tests */
+gboolean tpaw_live_search_match_string (const gchar *string,
+   const gchar *prefix);
+
+G_END_DECLS
+
+#endif /* __TPAW_LIVE_SEARCH_H__ */