comparison src/gtkrequest.c @ 11177:3924db2b1ca8

[gaim-migrate @ 13285] Performance optimizing the log set and screenname autocompletion code. committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Mon, 01 Aug 2005 04:08:27 +0000
parents e6b4badef34d
children 28ac54de3024
comparison
equal deleted inserted replaced
11176:6932df31225f 11177:3924db2b1ca8
42 typedef struct 42 typedef struct
43 { 43 {
44 GaimRequestType type; 44 GaimRequestType type;
45 45
46 void *user_data; 46 void *user_data;
47 GtkWidget *dialog; 47 GtkWidget *dialog;
48 48
49 GtkWidget *ok_button; 49 GtkWidget *ok_button;
50 50
51 size_t cb_count; 51 size_t cb_count;
52 GCallback *cbs; 52 GCallback *cbs;
645 645
646 gtk_widget_set_sensitive(req_data->ok_button, 646 gtk_widget_set_sensitive(req_data->ok_button,
647 gaim_request_fields_all_required_filled(field->group->fields_list)); 647 gaim_request_fields_all_required_filled(field->group->fields_list));
648 } 648 }
649 649
650 static GList *
651 get_screenname_completion_data(gboolean all)
652 {
653 GList *names = NULL;
654 GaimBlistNode *gnode, *cnode, *bnode;
655 GList *log_sets;
656 GList *log_set;
657
658 for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next)
659 {
660 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
661 continue;
662
663 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
664 {
665 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode))
666 continue;
667
668 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
669 {
670 GaimBuddy *buddy = (GaimBuddy *)bnode;
671
672 if (!all && !gaim_account_is_connected(buddy->account))
673 continue;
674
675 #ifdef NEW_STYLE_COMPLETION
676 names = g_list_append(names, ((GaimContact *)cnode)->alias);
677 names = g_list_append(names,
678 (gpointer)gaim_buddy_get_contact_alias(buddy));
679 names = g_list_append(names, buddy->account);
680 #endif /* NEW_STYLE_COMPLETION */
681
682 names = g_list_append(names, g_strdup(buddy->name));
683 }
684 }
685 }
686
687 if (all)
688 {
689 log_sets = gaim_log_get_log_sets();
690 for (log_set = log_sets ; log_set != NULL ; log_set = log_set->next) {
691 GaimLogSet *set = log_set->data;
692
693 /* 1. Don't show buddies because we will have gotten them above.
694 * 2. Only show those with non-NULL accounts that are currently connected.
695 * 3. The boxes that use this autocomplete code handle only IMs. */
696 if (!set->buddy &&
697 (set->account != NULL && gaim_account_is_connected(set->account)) &&
698 set->type != GAIM_LOG_CHAT) {
699 #ifdef NEW_STYLE_COMPLETION
700 names = g_list_append(names, NULL);
701 names = g_list_append(names, NULL);
702 names = g_list_append(names, set->account);
703 #endif /* NEW_STYLE_COMPLETION */
704
705 names = g_list_append(names, set->name);
706 }
707
708 g_free(set);
709 }
710 }
711
712 return names;
713 }
714
715 #ifndef NEW_STYLE_COMPLETION 650 #ifndef NEW_STYLE_COMPLETION
716 static gboolean 651 static gboolean
717 completion_entry_event(GtkEditable *entry, GdkEventKey *event, 652 completion_entry_event(GtkEditable *entry, GdkEventKey *event,
718 GaimGtkCompletionData *data) 653 GaimGtkCompletionData *data)
719 { 654 {
795 730
796 #ifdef NEW_STYLE_COMPLETION 731 #ifdef NEW_STYLE_COMPLETION
797 static gboolean screenname_completion_match_func(GtkEntryCompletion *completion, 732 static gboolean screenname_completion_match_func(GtkEntryCompletion *completion,
798 const gchar *key, GtkTreeIter *iter, gpointer user_data) { 733 const gchar *key, GtkTreeIter *iter, gpointer user_data) {
799 734
800 GValue val = { 0, }; 735 GValue val1 = { 0, };
736 GValue val2 = { 0, };
801 GtkTreeModel *model; 737 GtkTreeModel *model;
802 char *screenname = NULL;
803 char *alias = NULL;
804 char *temp;
805 gboolean ret = FALSE;
806 738
807 model = gtk_entry_completion_get_model (completion); 739 model = gtk_entry_completion_get_model (completion);
808 740
809 gtk_tree_model_get_value(model, iter, 1, &val); 741 gtk_tree_model_get_value(model, iter, 2, &val1);
810 temp = (gchar *)g_value_get_string(&val); 742 if (g_str_has_prefix(g_value_get_string(&val1), key))
811 if (temp) { 743 {
812 temp = g_utf8_normalize(temp, -1, G_NORMALIZE_DEFAULT); 744 g_value_unset(&val1);
813 screenname = g_utf8_casefold(temp, -1); 745 return TRUE;
814 g_free(temp); 746 }
815 } 747 g_value_unset(&val1);
816 g_value_unset(&val); 748
817 749 gtk_tree_model_get_value(model, iter, 3, &val2);
818 gtk_tree_model_get_value(model, iter, 2, &val); 750 if (g_str_has_prefix(g_value_get_string(&val2), key))
819 temp = (gchar *)g_value_get_string(&val); 751 {
820 if (temp) { 752 g_value_unset(&val2);
821 temp = g_utf8_normalize(temp, -1, G_NORMALIZE_DEFAULT); 753 return TRUE;
822 alias = g_utf8_casefold(temp, -1); 754 }
823 g_free(temp); 755 g_value_unset(&val2);
824 } 756
825 g_value_unset(&val); 757 return FALSE;
826
827 if (g_str_has_prefix(screenname, key) ||
828 g_str_has_prefix(alias, key))
829 ret = TRUE;
830
831 g_free(screenname);
832 g_free(alias);
833
834 return ret;
835 } 758 }
836 759
837 static gboolean screenname_completion_match_selected_cb(GtkEntryCompletion *completion, 760 static gboolean screenname_completion_match_selected_cb(GtkEntryCompletion *completion,
838 GtkTreeModel *model, GtkTreeIter *iter, gpointer *user_data) { 761 GtkTreeModel *model, GtkTreeIter *iter, gpointer *user_data) {
839 762
854 if (type_hint != NULL && !strcmp(type_hint, "account")) { 777 if (type_hint != NULL && !strcmp(type_hint, "account")) {
855 /* We found the corresponding account field. */ 778 /* We found the corresponding account field. */
856 GaimAccount *account; 779 GaimAccount *account;
857 GtkOptionMenu *optmenu = GTK_OPTION_MENU(field->ui_data); 780 GtkOptionMenu *optmenu = GTK_OPTION_MENU(field->ui_data);
858 781
859 gtk_tree_model_get_value(model, iter, 3, &val); 782 gtk_tree_model_get_value(model, iter, 4, &val);
860 account = g_value_get_pointer(&val); 783 account = g_value_get_pointer(&val);
861 g_value_unset(&val); 784 g_value_unset(&val);
862 785
863 /* Set the account in the request API. */ 786 /* Set the account in the request API. */
864 gaim_request_field_account_set_value(field, account); 787 gaim_request_field_account_set_value(field, account);
884 807
885 } while ((fields = fields->next) != NULL); 808 } while ((fields = fields->next) != NULL);
886 809
887 return TRUE; 810 return TRUE;
888 } 811 }
889 #endif /* !NEW_STYLE_COMPLETION */ 812
890 813 static void
891 static void 814 add_screenname_autocomplete_entry(GtkListStore *store, const char *buddy_alias, const char *contact_alias,
892 setup_screenname_autocomplete(GtkWidget *entry, GaimRequestField *field, gboolean all) 815 const GaimAccount *account, const char *screenname)
893 { 816 {
894 #ifdef NEW_STYLE_COMPLETION
895 GtkListStore *store;
896 GtkTreeIter iter; 817 GtkTreeIter iter;
897 GtkEntryCompletion *completion; 818 gboolean completion_added = FALSE;
898 GList *screenname_completion_data; 819 gchar *normalized_screenname;
899 GList *l; 820 gchar *tmp;
900 gpointer *data; 821
901 822 tmp = g_utf8_normalize(screenname, -1, G_NORMALIZE_DEFAULT);
902 /* Store the displayed completion value, the screenname, the value for comparison, and the account. */ 823 normalized_screenname = g_utf8_casefold(tmp, -1);
903 store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); 824 g_free(tmp);
904 825
905 screenname_completion_data = get_screenname_completion_data(all); 826 /* There's no sense listing things like: 'xxx "xxx"'
906 827 when the screenname and buddy alias match. */
907 /* Loop through the list four elements at a time. */ 828 if (buddy_alias && strcmp(buddy_alias, screenname)) {
908 for (l = screenname_completion_data; l != NULL; l = l->next->next->next->next) 829 char *completion_entry = g_strdup_printf("%s \"%s\"", screenname, buddy_alias);
909 { 830 char *tmp2 = g_utf8_normalize(buddy_alias, -1, G_NORMALIZE_DEFAULT);
910 char *contact_alias = l->data; 831
911 char *buddy_alias = l->next->data; 832 tmp = g_utf8_casefold(tmp2, -1);
912 GaimAccount *account = l->next->next->data; 833 g_free(tmp2);
913 char *screenname = l->next->next->next->data; 834
914 gboolean completion_added = FALSE; 835 gtk_list_store_append(store, &iter);
915 836 gtk_list_store_set(store, &iter,
916 /* There's no sense listing things like: 'xxx "xxx"' 837 0, completion_entry,
917 when the screenname and buddy alias match. */ 838 1, screenname,
918 if (buddy_alias && strcmp(buddy_alias, screenname)) { 839 2, normalized_screenname,
919 char *completion_entry = g_strdup_printf("%s \"%s\"", screenname, buddy_alias); 840 3, tmp,
841 4, account,
842 -1);
843 g_free(completion_entry);
844 g_free(tmp);
845 completion_added = TRUE;
846 }
847
848 /* There's no sense listing things like: 'xxx "xxx"'
849 when the screenname and contact alias match. */
850 if (contact_alias && strcmp(contact_alias, screenname)) {
851 /* We don't want duplicates when the contact and buddy alias match. */
852 if (!buddy_alias || strcmp(contact_alias, buddy_alias)) {
853 char *completion_entry = g_strdup_printf("%s \"%s\"",
854 screenname, contact_alias);
855 char *tmp2 = g_utf8_normalize(contact_alias, -1, G_NORMALIZE_DEFAULT);
856
857 tmp = g_utf8_casefold(tmp2, -1);
858 g_free(tmp2);
859
920 gtk_list_store_append(store, &iter); 860 gtk_list_store_append(store, &iter);
921 gtk_list_store_set(store, &iter, 861 gtk_list_store_set(store, &iter,
922 0, completion_entry, 862 0, completion_entry,
923 1, screenname, 863 1, screenname,
924 2, buddy_alias, 864 2, normalized_screenname,
925 3, account, 865 3, tmp,
866 4, account,
926 -1); 867 -1);
927 g_free(completion_entry); 868 g_free(completion_entry);
869 g_free(tmp);
928 completion_added = TRUE; 870 completion_added = TRUE;
929 } 871 }
930 872 }
931 /* There's no sense listing things like: 'xxx "xxx"' 873
932 when the screenname and contact alias match. */ 874 if (completion_added == FALSE) {
933 if (contact_alias && strcmp(contact_alias, screenname)) { 875 /* Add the buddy's screenname. */
934 /* We don't want duplicates when the contact and buddy alias match. */ 876 gtk_list_store_append(store, &iter);
935 if (strcmp(contact_alias, buddy_alias)) { 877 gtk_list_store_set(store, &iter,
936 char *completion_entry = g_strdup_printf("%s \"%s\"", 878 0, screenname,
937 screenname, contact_alias); 879 1, screenname,
938 gtk_list_store_append(store, &iter); 880 2, normalized_screenname,
939 gtk_list_store_set(store, &iter, 881 3, NULL,
940 0, completion_entry, 882 4, account,
941 1, screenname, 883 -1);
942 2, contact_alias, 884 }
943 3, account, 885
944 -1); 886 g_free(normalized_screenname);
945 g_free(completion_entry); 887 }
946 completion_added = TRUE; 888 #endif /* NEW_STYLE_COMPLETION */
889
890 static void get_log_set_name(GaimLogSet *set, gpointer value, gpointer **set_hash_data)
891 {
892 /* 1. Don't show buddies because we will have gotten them already.
893 * 2. Only show those with non-NULL accounts that are currently connected.
894 * 3. The boxes that use this autocomplete code handle only IMs. */
895 if (!set->buddy &&
896 (GPOINTER_TO_INT(set_hash_data[1]) ||
897 (set->account != NULL && gaim_account_is_connected(set->account))) &&
898 set->type == GAIM_LOG_IM) {
899 #if NEW_STYLE_COMPLETION
900 add_screenname_autocomplete_entry((GtkListStore *)set_hash_data[0],
901 NULL, NULL, set->account, set->name);
902 #else
903 GList **items = ((GList **)set_hash_data[0]);
904 /* Steal the name for the GCompletion. */
905 *items = g_list_append(*items, set->name);
906 set->name = set->normalized_name = NULL;
907 #endif /* NEW_STYLE_COMPLETION */
908 }
909 }
910
911 static void
912 setup_screenname_autocomplete(GtkWidget *entry, GaimRequestField *field, gboolean all)
913 {
914 #ifdef NEW_STYLE_COMPLETION
915 /* Store the displayed completion value, the screenname, the UTF-8 normalized & casefolded screenname,
916 * the UTF-8 normalized & casefolded value for comparison, and the account. */
917 GtkListStore *store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
918
919 GaimBlistNode *gnode, *cnode, *bnode;
920 GHashTable *sets;
921 gpointer set_hash_data[] = {store, GINT_TO_POINTER(all)};
922 GtkEntryCompletion *completion;
923 gpointer *data;
924
925 for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next)
926 {
927 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
928 continue;
929
930 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
931 {
932 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode))
933 continue;
934
935 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
936 {
937 GaimBuddy *buddy = (GaimBuddy *)bnode;
938
939 if (!all && !gaim_account_is_connected(buddy->account))
940 continue;
941
942 add_screenname_autocomplete_entry(store,
943 ((GaimContact *)cnode)->alias,
944 gaim_buddy_get_contact_alias(buddy),
945 buddy->account,
946 buddy->name
947 );
947 } 948 }
948 } 949 }
949 950 }
950 if (completion_added == FALSE) { 951
951 /* Add the buddy's screenname. */ 952 sets = gaim_log_get_log_sets();
952 gtk_list_store_append(store, &iter); 953 g_hash_table_foreach(sets, (GHFunc)get_log_set_name, &set_hash_data);
953 gtk_list_store_set(store, &iter, 954 g_hash_table_destroy(sets);
954 0, screenname, 955
955 1, screenname,
956 2, NULL,
957 3, account,
958 -1);
959 }
960
961 g_free(screenname);
962 }
963
964 g_list_free(screenname_completion_data);
965 956
966 /* Sort the completion list by screenname. */ 957 /* Sort the completion list by screenname. */
967 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 958 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
968 1, GTK_SORT_ASCENDING); 959 1, GTK_SORT_ASCENDING);
969 960
984 975
985 gtk_entry_completion_set_text_column(completion, 0); 976 gtk_entry_completion_set_text_column(completion, 0);
986 977
987 #else /* !NEW_STYLE_COMPLETION */ 978 #else /* !NEW_STYLE_COMPLETION */
988 GaimGtkCompletionData *data; 979 GaimGtkCompletionData *data;
989 GList *screennames; 980 GaimBlistNode *gnode, *cnode, *bnode;
981 GList *item = g_list_append(NULL, NULL);
982 GHashTable *sets;
983 gpointer set_hash_data[2];
990 984
991 data = g_new0(GaimGtkCompletionData, 1); 985 data = g_new0(GaimGtkCompletionData, 1);
992 986
993 data->completion = g_completion_new(NULL); 987 data->completion = g_completion_new(NULL);
994 988
995 g_completion_set_compare(data->completion, g_ascii_strncasecmp); 989 g_completion_set_compare(data->completion, g_ascii_strncasecmp);
996 990
997 screennames = get_screenname_completion_data(all); 991 for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next)
998 992 {
999 g_completion_add_items(data->completion, screennames); 993 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
1000 994 continue;
1001 g_list_free(screennames); 995
996 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
997 {
998 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode))
999 continue;
1000
1001 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
1002 {
1003 GaimBuddy *buddy = (GaimBuddy *)bnode;
1004
1005 if (!all && !gaim_account_is_connected(buddy->account))
1006 continue;
1007
1008 item->data = g_strdup(buddy->name);
1009 g_completion_add_items(data->completion, item);
1010 }
1011 }
1012 }
1013 g_list_free(item);
1014
1015 sets = gaim_log_get_log_sets();
1016 item = NULL;
1017 set_hash_data[0] = &item;
1018 set_hash_data[1] = GINT_TO_POINTER(all);
1019 g_hash_table_foreach(sets, (GHFunc)get_log_set_name, &set_hash_data);
1020 g_hash_table_destroy(sets);
1021 g_completion_add_items(data->completion, item);
1022 g_list_free(item);
1002 1023
1003 g_signal_connect(G_OBJECT(entry), "event", 1024 g_signal_connect(G_OBJECT(entry), "event",
1004 G_CALLBACK(completion_entry_event), data); 1025 G_CALLBACK(completion_entry_event), data);
1005 g_signal_connect(G_OBJECT(entry), "destroy", 1026 g_signal_connect(G_OBJECT(entry), "destroy",
1006 G_CALLBACK(destroy_completion_data), data); 1027 G_CALLBACK(destroy_completion_data), data);