| 2962 } |
2962 } |
| 2963 va_end(args); |
2963 va_end(args); |
| 2964 |
2964 |
| 2965 return vbox; |
2965 return vbox; |
| 2966 } |
2966 } |
| |
2967 |
| |
2968 /* |
| |
2969 * "This is so dead sexy." |
| |
2970 * "Two thumbs up." |
| |
2971 * "Best movie of the year." |
| |
2972 * |
| |
2973 * This is the function that handles CTRL+F searching in the buddy list. |
| |
2974 * It finds the top-most buddy/group/chat/whatever containing the |
| |
2975 * entered string. |
| |
2976 * |
| |
2977 * It's somewhat ineffecient, because we strip all the HTML from the |
| |
2978 * "name" column of the buddy list (because the GtkTreeModel does not |
| |
2979 * contain the screen name in a non-markedup format). But the alternative |
| |
2980 * is to add an extra column to the GtkTreeModel. And this function is |
| |
2981 * used rarely, so it shouldn't matter TOO much. |
| |
2982 */ |
| |
2983 gboolean gaim_gtk_tree_view_search_equal_func(GtkTreeModel *model, gint column, |
| |
2984 const gchar *key, GtkTreeIter *iter, gpointer data) |
| |
2985 { |
| |
2986 gchar *enteredstring; |
| |
2987 gchar *tmp; |
| |
2988 gchar *withmarkup; |
| |
2989 gchar *nomarkup; |
| |
2990 gchar *normalized; |
| |
2991 gboolean result; |
| |
2992 size_t i; |
| |
2993 size_t len; |
| |
2994 PangoLogAttr *log_attrs; |
| |
2995 gchar *word; |
| |
2996 |
| |
2997 if (strcasecmp(key, "Global Thermonuclear War") == 0) |
| |
2998 { |
| |
2999 gaim_notify_info(NULL, "WOPR", |
| |
3000 "Wouldn't you prefer a nice game of chess?", NULL); |
| |
3001 return FALSE; |
| |
3002 } |
| |
3003 |
| |
3004 gtk_tree_model_get(model, iter, column, &withmarkup, -1); |
| |
3005 if (withmarkup == NULL) /* This is probably a separator */ |
| |
3006 return TRUE; |
| |
3007 |
| |
3008 tmp = g_utf8_normalize(key, -1, G_NORMALIZE_DEFAULT); |
| |
3009 enteredstring = g_utf8_casefold(tmp, -1); |
| |
3010 g_free(tmp); |
| |
3011 |
| |
3012 nomarkup = gaim_markup_strip_html(withmarkup); |
| |
3013 tmp = g_utf8_normalize(nomarkup, -1, G_NORMALIZE_DEFAULT); |
| |
3014 g_free(nomarkup); |
| |
3015 normalized = g_utf8_casefold(tmp, -1); |
| |
3016 g_free(tmp); |
| |
3017 |
| |
3018 if (gaim_str_has_prefix(normalized, enteredstring)) |
| |
3019 { |
| |
3020 g_free(withmarkup); |
| |
3021 g_free(enteredstring); |
| |
3022 g_free(normalized); |
| |
3023 return FALSE; |
| |
3024 } |
| |
3025 |
| |
3026 |
| |
3027 /* Use Pango to separate by words. */ |
| |
3028 len = g_utf8_strlen(normalized, -1); |
| |
3029 log_attrs = g_new(PangoLogAttr, len + 1); |
| |
3030 |
| |
3031 pango_get_log_attrs(normalized, strlen(normalized), -1, NULL, log_attrs, len + 1); |
| |
3032 |
| |
3033 word = normalized; |
| |
3034 result = TRUE; |
| |
3035 for (i = 0; i < (len - 1) ; i++) |
| |
3036 { |
| |
3037 if (log_attrs[i].is_word_start && |
| |
3038 gaim_str_has_prefix(word, enteredstring)) |
| |
3039 { |
| |
3040 result = FALSE; |
| |
3041 break; |
| |
3042 } |
| |
3043 word = g_utf8_next_char(word); |
| |
3044 } |
| |
3045 g_free(log_attrs); |
| |
3046 |
| |
3047 /* The non-Pango version. */ |
| |
3048 #if 0 |
| |
3049 word = normalized; |
| |
3050 result = TRUE; |
| |
3051 while (word[0] != '\0') |
| |
3052 { |
| |
3053 gunichar c = g_utf8_get_char(word); |
| |
3054 if (!g_unichar_isalnum(c)) |
| |
3055 { |
| |
3056 word = g_utf8_find_next_char(word, NULL); |
| |
3057 if (gaim_str_has_prefix(word, enteredstring)) |
| |
3058 { |
| |
3059 result = FALSE; |
| |
3060 break; |
| |
3061 } |
| |
3062 } |
| |
3063 else |
| |
3064 word = g_utf8_find_next_char(word, NULL); |
| |
3065 } |
| |
3066 #endif |
| |
3067 |
| |
3068 g_free(withmarkup); |
| |
3069 g_free(enteredstring); |
| |
3070 g_free(normalized); |
| |
3071 |
| |
3072 return result; |
| |
3073 } |
| |
3074 |