# HG changeset patch # User Bartoz Oler # Date 1125267684 0 # Node ID 9480e0d0f563412e66cebd53b23da0278e12d292 # Parent fb702c34794bc23104ce95deccadae29ea742890 [gaim-migrate @ 13581] Search results notification extended so that any column can be added. committer: Tailor Script diff -r fb702c34794b -r 9480e0d0f563 src/gtknotify.c --- a/src/gtknotify.c Sun Aug 28 22:18:08 2005 +0000 +++ b/src/gtknotify.c Sun Aug 28 22:21:24 2005 +0000 @@ -56,12 +56,12 @@ } GaimNotifySearchResultsData; -enum +typedef struct { - COLUMN_ICON, - COLUMN_SCREENNAME, - NUM_COLUMNS -}; + GaimNotifySearchButton *button; + GaimNotifySearchResultsData *data; + +} GaimNotifySearchResultsButtonData; static void *gaim_gtk_notify_emails(size_t count, gboolean detailed, const char **subjects, @@ -97,12 +97,17 @@ } static void -add_buddy_helper_cb(GtkWidget *widget, GaimNotifySearchResultsData *data) +searchresults_callback_wrapper_cb(GtkWidget *widget, GaimNotifySearchResultsButtonData *bd) { + GaimNotifySearchResultsData *data = bd->data; + GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; - gchar *buddy; + GaimNotifySearchButton *button; + GList *row = NULL; + gchar *str; + int i; g_return_if_fail(data != NULL); @@ -110,11 +115,14 @@ if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, - COLUMN_SCREENNAME, &buddy, -1); - gaim_blist_request_add_buddy(data->account, buddy, NULL, NULL); - g_free(buddy); + for (i = 1; i < gtk_tree_model_get_n_columns(GTK_TREE_MODEL(model)); i++) { + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, i, &str, -1); + row = g_list_append(row, str); + } } + + button = bd->button; + button->callback(gaim_account_get_connection(data->account), row); } static void * @@ -426,26 +434,64 @@ return window; } +static void +gaim_gtk_notify_searchresults_new_rows(GaimConnection *gc, GaimNotifySearchResults *results, + void *data_, void *user_data) +{ + GaimNotifySearchResultsData *data = data_; + GtkListStore *model = data->model; + GtkTreeIter iter; + GdkPixbuf *icon, *scaled; + int col_num; + int i, j; + + gtk_list_store_clear(data->model); + + icon = gaim_gtk_create_prpl_icon(gaim_connection_get_account(gc)); + scaled = gdk_pixbuf_scale_simple(icon, 16, 16, GDK_INTERP_BILINEAR); + + /* +1 is for the automagically created Status column. */ + col_num = gaim_notify_searchresults_get_columns_count(results) + 1; + + for (i = 0; i < gaim_notify_searchresults_get_rows_count(results); i++) { + GList *row = gaim_notify_searchresults_row_get(results, i); + + gtk_list_store_append(model, &iter); + gtk_list_store_set(model, &iter, 0, scaled, -1); + + for (j = 1; j < col_num; j++) { + GValue v = {0, }; + char *escaped = g_markup_escape_text(g_list_nth_data(row, j - 1), -1); + + g_value_init(&v, G_TYPE_STRING); + g_value_set_string(&v, escaped); + gtk_list_store_set_value(model, &iter, j, &v); + g_free(escaped); + } + } +} + static void * gaim_gtk_notify_searchresults(GaimConnection *gc, const char *title, const char *primary, const char *secondary, - const char **results, GCallback cb, + GaimNotifySearchResults *results, GCallback cb, void *user_data) { GtkWidget *window; + GtkWidget *treeview; + GtkWidget *button, *close_button; + GType *col_types; + GtkListStore *model; + GtkCellRenderer *renderer; + int col_num; + int i; + GList *buttons = NULL; + GtkWidget *vbox; GtkWidget *button_area; GtkWidget *label; - GtkWidget *close_button; - GtkWidget *add_button; GtkWidget *sw; - GtkWidget *treeview; - GdkPixbuf *icon, *scaled; GaimNotifySearchResultsData *data; - GtkListStore *model; - GtkCellRenderer *renderer; - GtkTreeIter iter; - int i; char *label_text; char *primary_esc, *secondary_esc; @@ -483,8 +529,18 @@ gtk_widget_show(label); g_free(label_text); + /* +1 is for the automagically created Status column. */ + col_num = gaim_notify_searchresults_get_columns_count(results) + 1; + /* Setup the list model */ - model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING); + col_types = g_new0(GType, col_num); + + /* There always is this first column. */ + col_types[0] = GDK_TYPE_PIXBUF; + for (i = 1; i < col_num; i++) { + col_types[i] = G_TYPE_STRING; + } + model = gtk_list_store_newv(col_num, col_types); /* Setup the scrolled window containing the treeview */ sw = gtk_scrolled_window_new(NULL, NULL); @@ -498,27 +554,25 @@ /* Setup the treeview */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); - gtk_widget_set_size_request(treeview, 250, 150); + gtk_widget_set_size_request(treeview, 500, 400); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_SINGLE); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); - /* icon column */ - renderer = gtk_cell_renderer_pixbuf_new (); + renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), - -1, "Icon", renderer, - "pixbuf", COLUMN_ICON, - NULL); + -1, "", renderer, "pixbuf", 0, NULL); - /* screenname column */ - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), - -1, "Screenname", renderer, - "text", COLUMN_SCREENNAME, - NULL); + for (i = 1; i < col_num; i++) { + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1, + gaim_notify_searchresults_column_get_title(results, i-1), + renderer, "text", i, NULL); + } + /* Setup the button area */ button_area = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(vbox), button_area, FALSE, FALSE, 0); @@ -526,39 +580,48 @@ gtk_box_set_spacing(GTK_BOX(button_area), GAIM_HIG_BORDER); gtk_widget_show(button_area); - /* Add the Add button */ - add_button = gtk_button_new_from_stock(GTK_STOCK_ADD); - gtk_box_pack_start(GTK_BOX(button_area), add_button, FALSE, FALSE, 0); - gtk_widget_show(add_button); + for (i = 0; i < g_list_length(results->buttons); i++) { + GaimNotifySearchButton *b = g_list_nth_data(results->buttons, i); + button = NULL; + switch (b->type) { + case GAIM_NOTIFY_BUTTON_CONTINUE: + button = gtk_button_new_from_stock(GTK_STOCK_GO_FORWARD); + break; + case GAIM_NOTIFY_BUTTON_ADD_BUDDY: + button = gtk_button_new_from_stock(GTK_STOCK_ADD); + break; + default: + gaim_debug_warning("gtknotify", "Incorrect button type: %d\n", b->type); + } + if (button != NULL) { + gtk_box_pack_start(GTK_BOX(button_area), button, FALSE, FALSE, 0); + gtk_widget_show(button); + buttons = g_list_append(buttons, button); + } + } /* Add the Close button */ close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); gtk_box_pack_start(GTK_BOX(button_area), close_button, FALSE, FALSE, 0); gtk_widget_show(close_button); - /* Add the buddies to the tree view */ - icon = gaim_gtk_create_prpl_icon(gc->account); - scaled = gdk_pixbuf_scale_simple(icon, 16, 16, GDK_INTERP_BILINEAR); - - for (i = 0; results[i] != NULL; i++) - { - char *escaped = g_markup_escape_text(results[i], -1); - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - COLUMN_ICON, scaled, - COLUMN_SCREENNAME, escaped, - -1); - g_free(escaped); - } - data->account = gc->account; data->model = model; data->treeview = treeview; data->window = window; + /* Insert rows. */ + gaim_gtk_notify_searchresults_new_rows(gc, results, data, NULL); + /* Connect Signals */ - g_signal_connect(G_OBJECT(add_button), "clicked", - G_CALLBACK(add_buddy_helper_cb), data); + for (i = 0; i < g_list_length(results->buttons); i++) { + GaimNotifySearchResultsButtonData *bd = g_new0(GaimNotifySearchResultsButtonData, 1); + bd->button = g_list_nth_data(results->buttons, i); + bd->data = data; + g_signal_connect(G_OBJECT(g_list_nth_data(buttons, i)), "clicked", + G_CALLBACK(searchresults_callback_wrapper_cb), bd); + } + g_signal_connect_swapped(G_OBJECT(close_button), "clicked", G_CALLBACK(searchresults_close_cb), data); @@ -811,6 +874,7 @@ gaim_gtk_notify_emails, gaim_gtk_notify_formatted, gaim_gtk_notify_searchresults, + gaim_gtk_notify_searchresults_new_rows, gaim_gtk_notify_userinfo, gaim_gtk_notify_uri, gaim_gtk_close_notify diff -r fb702c34794b -r 9480e0d0f563 src/notify.c --- a/src/notify.c Sun Aug 28 22:18:08 2005 +0000 +++ b/src/notify.c Sun Aug 28 22:21:24 2005 +0000 @@ -158,7 +158,7 @@ void * gaim_notify_searchresults(GaimConnection *gc, const char *title, const char *primary, const char *secondary, - const char **results, GCallback cb, void *user_data) + GaimNotifySearchResults *results, GCallback cb, void *user_data) { GaimNotifyUiOps *ops; @@ -182,6 +182,151 @@ return NULL; } +void +gaim_notify_searchresults_free(GaimNotifySearchResults *results) +{ + GList *l, *m; + + g_return_if_fail(results != NULL); + + for (l = results->buttons; l != NULL; l = l->next) { + GaimNotifySearchButton *button = l->data; + + results->buttons = g_list_remove(results->buttons, button); + g_free(button); + } + g_list_free(results->buttons); + + for (l = results->rows; l != NULL; l = l->next) { + GList *row = l->data; + + for (m = row; m != NULL; m = m->next) { + gchar *str = m->data; + + m = g_list_remove(m, str); + g_free(str); + } + + results->rows = g_list_remove(results->rows, row); + g_list_free(row); + } + g_list_free(results->rows); + + for (l = results->columns; l != NULL; l = l->next) { + GaimNotifySearchColumn *column = l->data; + + results->columns = g_list_remove(results->columns, column); + g_free(column->title); + g_free(column); + } + g_list_free(results->columns); +} + +void +gaim_notify_searchresults_new_rows(GaimConnection *gc, + GaimNotifySearchResults *results, + void *data, void *user_data) +{ + GaimNotifyUiOps *ops; + + ops = gaim_notify_get_ui_ops(); + + if (ops != NULL && ops->notify_searchresults != NULL) { + ops->notify_searchresults_new_rows(gc, results, data, user_data); + } +} + +void +gaim_notify_searchresults_button_add(GaimNotifySearchResults *results, + GaimNotifySearchButtonType type, + GaimNotifySearchResultsCallback cb) +{ + GaimNotifySearchButton *button; + + g_return_if_fail(results != NULL); + g_return_if_fail(cb != NULL); + + button = g_new0(GaimNotifySearchButton, 1); + button->callback = cb; + button->type = type; + + results->buttons = g_list_append(results->buttons, button); +} + +GaimNotifySearchResults * +gaim_notify_searchresults_new() +{ + GaimNotifySearchResults *rs = g_new0(GaimNotifySearchResults, 1); + + return rs; +} + +void +gaim_notify_searchresults_column_add(GaimNotifySearchResults *results, + GaimNotifySearchColumn *column) +{ + g_return_if_fail(results != NULL); + g_return_if_fail(column != NULL); + + results->columns = g_list_append(results->columns, column); +} + +void gaim_notify_searchresults_row_add(GaimNotifySearchResults *results, + GList *row) +{ + g_return_if_fail(results != NULL); + g_return_if_fail(row != NULL); + + results->rows = g_list_append(results->rows, row); +} + +GaimNotifySearchColumn * +gaim_notify_searchresults_column_new(const char *title) +{ + GaimNotifySearchColumn *sc; + + g_return_val_if_fail(title != NULL, NULL); + + sc = g_new0(GaimNotifySearchColumn, 1); + sc->title = g_strdup(title); + + return sc; +} + +int +gaim_notify_searchresults_get_columns_count(GaimNotifySearchResults *results) +{ + g_return_val_if_fail(results != NULL, -1); + + return g_list_length(results->columns); +} + +int +gaim_notify_searchresults_get_rows_count(GaimNotifySearchResults *results) +{ + g_return_val_if_fail(results != NULL, -1); + + return g_list_length(results->rows); +} + +char * +gaim_notify_searchresults_column_get_title(GaimNotifySearchResults *results, + unsigned int column_id) +{ + g_return_val_if_fail(results != NULL, NULL); + + return ((GaimNotifySearchColumn *)g_list_nth_data(results->columns, column_id))->title; +} + +GList * +gaim_notify_searchresults_row_get(GaimNotifySearchResults *results, + unsigned int row_id) +{ + g_return_val_if_fail(results != NULL, NULL); + + return g_list_nth_data(results->rows, row_id); +} + void * gaim_notify_userinfo(GaimConnection *gc, const char *who, const char *title, const char *primary, const char *secondary, diff -r fb702c34794b -r 9480e0d0f563 src/notify.h --- a/src/notify.h Sun Aug 28 22:18:08 2005 +0000 +++ b/src/notify.h Sun Aug 28 22:21:24 2005 +0000 @@ -58,6 +58,49 @@ } GaimNotifyMsgType; /** + * The types of buttons + */ +typedef enum +{ + GAIM_NOTIFY_BUTTON_CONTINUE = 0, + GAIM_NOTIFY_BUTTON_ADD_BUDDY + +} GaimNotifySearchButtonType; + +/** + * Search results object. + */ +typedef struct +{ + GList *columns; /**< List of the search column objects. */ + GList *rows; /**< List of rows in the result. */ + GList *buttons; /**< List of buttons to display. */ + +} GaimNotifySearchResults; + +/** + * Single column of a search result. + */ +typedef struct +{ + char *title; /**< Title of the column. */ + +} GaimNotifySearchColumn; + +typedef void (*GaimNotifySearchResultsCallback)(GaimConnection *, GList *); + + +/** + * Definition of a button. + */ +typedef struct +{ + GaimNotifySearchButtonType type; + GaimNotifySearchResultsCallback callback; /**< Function to be called when clicked. */ + +} GaimNotifySearchButton; + +/** * Notification UI operations. */ typedef struct @@ -77,8 +120,11 @@ GCallback cb, void *user_data); void *(*notify_searchresults)(GaimConnection *gc, const char *title, const char *primary, const char *secondary, - const char **results, GCallback cb, + GaimNotifySearchResults *results, GCallback cb, void *user_data); + void (*notify_searchresults_new_rows)(GaimConnection *gc, + GaimNotifySearchResults *results, + void *data, void *user_data); void *(*notify_userinfo)(GaimConnection *gc, const char *who, const char *title, const char *primary, const char *secondary, const char *text, @@ -89,12 +135,139 @@ } GaimNotifyUiOps; - #ifdef __cplusplus extern "C" { #endif /**************************************************************************/ +/** Search results notification API */ +/**************************************************************************/ +/*@{*/ + +/** + * Displays results from a buddy search. This can be, for example, + * a window with a list of all found buddies, where you are given the + * option of adding buddies to your buddy list. + * + * @param gc The GaimConnection handle associated with the information. + * @param title The title of the message. If this is NULL, the title + * will be "Search Results." + * @param primary The main point of the message. + * @param secondary The secondary information. + * @param results The GaimNotifySearchResults instance. + * @param cb The callback to call when the user closes + * the notification. + * @param user_data The data to pass to the callback. + * + * @return A UI-specific handle. + */ +void *gaim_notify_searchresults(GaimConnection *gc, const char *title, + const char *primary, const char *secondary, + GaimNotifySearchResults *results, GCallback cb, + void *user_data); + +void gaim_notify_searchresults_free(GaimNotifySearchResults *results); + +/** + * Replace old rows with the new. Reuse an existing window. + * + * @param gc The GaimConnection structure. + * @param results The GaimNotifySearchResults structure. + * @param data Data returned by the gaim_notify_searchresults(). + * @param user_data User defined data. + */ +void gaim_notify_searchresults_new_rows(GaimConnection *gc, + GaimNotifySearchResults *results, + void *data, void *user_data); + +/** + * Adds a button that will be displayed in the search results dialog. + * + * @param results The search results object. + * @param type Type of the button. (TODO: Only one button of a given type can be displayed.) + * @param cb Function that will be called on the click event. + */ +void gaim_notify_searchresults_button_add(GaimNotifySearchResults *results, + GaimNotifySearchButtonType type, + GaimNotifySearchResultsCallback cb); + +/** + * Returns a newly created search results object. + * + * @return The new search results object. + */ +GaimNotifySearchResults *gaim_notify_searchresults_new(); + +/** + * Returns a newly created search result column object. + * + * @param title Title of the column. NOTE: Title will get g_strdup()ed. + * + * @return The new search column object. + */ +GaimNotifySearchColumn *gaim_notify_searchresults_column_new(const char *title); + +/** + * Adds a new column to the search result object. + * + * @param results The result object to which the column will be added. + * @param columnt The column that will be added to the result object. + */ +void gaim_notify_searchresults_column_add(GaimNotifySearchResults *results, + GaimNotifySearchColumn *column); + +/** + * Adds a new row of the results to the search results object. + * + * @param results The search results object. + * @param row The row of the results. + */ +void gaim_notify_searchresults_row_add(GaimNotifySearchResults *results, + GList *row); + +/** + * Returns a number of the rows in the search results object. + * + * @param results The search results object. + * + * @return Number of the result rows. Or -1 if an error occurrs. + */ +int gaim_notify_searchresults_get_rows_count(GaimNotifySearchResults *results); + +/** + * Returns a number of the columns in the search results object. + * + * @param results The search results object. + * + * @return Number of the columns. Or -1 if an error occurrs. + */ +int gaim_notify_searchresults_get_columns_count(GaimNotifySearchResults *results); + +/** + * Returns a row of the results from the search results object. + * + * @param results The search results object. + * @param row_id Index of the row to be returned. + * + * @return Row of the results. + */ +GList *gaim_notify_searchresults_row_get(GaimNotifySearchResults *results, + unsigned int row_id); + +/** + * Returns a title of the search results object's column. + * + * @param results The search results object. + * @param column_id Index of the column. + * + * @return Title of the column. + */ +char *gaim_notify_searchresults_column_get_title(GaimNotifySearchResults *results, + unsigned int column_id); + +/*@}*/ + +/**************************************************************************/ /** @name Notification API */ /**************************************************************************/ /*@{*/ @@ -181,28 +354,6 @@ const char *text, GCallback cb, void *user_data); /** - * Displays results from a buddy search. This can be, for example, - * a window with a list of all found buddies, where you are given the - * option of adding buddies to your buddy list. - * - * @param gc The GaimConnection handle associated with the information. - * @param title The title of the message. If this is NULL, the title - * will be "Search Results." - * @param primary The main point of the message. - * @param secondary The secondary information. - * @param results An null-terminated array of null-terminated buddy names. - * @param cb The callback to call when the user closes - * the notification. - * @param user_data The data to pass to the callback. - * - * @return A UI-specific handle. - */ -void *gaim_notify_searchresults(GaimConnection *gc, const char *title, - const char *primary, const char *secondary, - const char **results, GCallback cb, - void *user_data); - -/** * Displays user information with formatted text, passing information giving * the connection and username from which the user information came. * diff -r fb702c34794b -r 9480e0d0f563 src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Sun Aug 28 22:18:08 2005 +0000 +++ b/src/protocols/oscar/oscar.c Sun Aug 28 22:21:24 2005 +0000 @@ -5449,11 +5449,18 @@ return 1; } +static void oscar_searchresults_add_buddy_cb(GaimConnection *gc, GList *row) +{ + gaim_blist_request_add_buddy(gaim_connection_get_account(gc), + g_list_nth_data(row, 0), NULL, NULL); +} + static int gaim_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...) { GaimConnection *gc = sess->aux_data; + GaimNotifySearchResults *results; + GaimNotifySearchColumn *column; gchar *secondary; - gchar **screennames; int i, num; va_list ap; char *email, *SNs; @@ -5467,16 +5474,20 @@ /* TODO: Need to use ngettext() here */ secondary = g_strdup_printf(_("The following screen names are associated with %s"), email); - screennames = g_malloc((num + 1) * sizeof(gchar *)); - for (i = 0; i < num; i++) - screennames[i] = g_strdup(&SNs[i * (MAXSNLEN + 1)]); - screennames[num] = NULL; - - gaim_notify_searchresults(gc, NULL, NULL, secondary, - (const char **)screennames, NULL, NULL); + results = gaim_notify_searchresults_new(); + column = gaim_notify_searchresults_column_new("Screen name"); + gaim_notify_searchresults_column_add(results, column); + + for (i = 0; i < num; i++) { + GList *row = NULL; + row = g_list_append(row, g_strdup(&SNs[i * (MAXSNLEN + 1)])); + gaim_notify_searchresults_row_add(results, row); + } + gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_ADD_BUDDY, + oscar_searchresults_add_buddy_cb); + gaim_notify_searchresults(gc, NULL, NULL, secondary, results, NULL, NULL); g_free(secondary); - g_strfreev(screennames); return 1; }