# HG changeset patch # User Sadrul Habib Chowdhury # Date 1160623593 0 # Node ID b15c2eaeb67fe2f2a89fb2b1951e852c4c7b0765 # Parent 556a112ab6ca9a561580c490835d67b019e716a6 [gaim-migrate @ 17466] Patch #1573404 from Richard Nelson (wabz): "This patch keeps the blist sorted (sorts rows at the current depth when the text for a given row changes). Adds a menu "Options" to the blist and adds the options to sort by status, alphabetically and toggle offline buddies." I changed some of the stuff from the patch. Hopefully I didn't break anything. I also added a "Sort by log size" option. committer: Tailor Script diff -r 556a112ab6ca -r b15c2eaeb67f console/gntblist.c --- a/console/gntblist.c Thu Oct 12 02:51:52 2006 +0000 +++ b/console/gntblist.c Thu Oct 12 03:26:33 2006 +0000 @@ -99,6 +99,11 @@ static const char * get_display_name(GaimBlistNode *node); static void savedstatus_changed(GaimSavedStatus *now, GaimSavedStatus *old); +/* Sort functions */ +static int blist_node_compare_text(GaimBlistNode *n1, GaimBlistNode *n2); +static int blist_node_compare_status(GaimBlistNode *n1, GaimBlistNode *n2); +static int blist_node_compare_log(GaimBlistNode *n1, GaimBlistNode *n2); + static gboolean is_contact_online(GaimContact *contact) { @@ -188,6 +193,7 @@ if (node->ui_data != NULL) { gnt_tree_change_text(GNT_TREE(ggblist->tree), node, 0, get_display_name(node)); + gnt_tree_sort_row(GNT_TREE(ggblist->tree), node); } if (GAIM_BLIST_NODE_IS_BUDDY(node)) { @@ -1375,6 +1381,17 @@ GaimBlistNode *node; GaimBuddyList *list; + if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "text") == 0) { + gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), + (GCompareFunc)blist_node_compare_text); + } else if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "status") == 0) { + gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), + (GCompareFunc)blist_node_compare_status); + } else if (strcmp(gaim_prefs_get_string(PREF_ROOT "/sort_type"), "log") == 0) { + gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), + (GCompareFunc)blist_node_compare_log); + } + list = gaim_get_blist(); node = gaim_blist_get_root(); while (node) @@ -1475,11 +1492,14 @@ gaim_prefs_add_int(PREF_ROOT "/position/y", 0); gaim_prefs_add_bool(PREF_ROOT "/idletime", TRUE); gaim_prefs_add_bool(PREF_ROOT "/showoffline", FALSE); + gaim_prefs_add_string(PREF_ROOT "/sort_type", "text"); gg_blist_show(); gaim_prefs_connect_callback(gg_blist_get_handle(), PREF_ROOT "/showoffline", redraw_blist, NULL); + gaim_prefs_connect_callback(gg_blist_get_handle(), + PREF_ROOT "/sort_type", redraw_blist, NULL); return; } @@ -1621,7 +1641,7 @@ } static int -blist_node_compare(GaimBlistNode *n1, GaimBlistNode *n2) +blist_node_compare_text(GaimBlistNode *n1, GaimBlistNode *n2) { const char *s1, *s2; char *us1, *us2; @@ -1640,7 +1660,6 @@ s2 = gaim_chat_get_name((GaimChat*)n2); break; case GAIM_BLIST_BUDDY_NODE: - /* XXX: reordering existing rows don't do well in GntTree */ return gaim_presence_compare(gaim_buddy_get_presence((GaimBuddy*)n1), gaim_buddy_get_presence((GaimBuddy*)n2)); break; @@ -1661,6 +1680,77 @@ return ret; } +static int +blist_node_compare_status(GaimBlistNode *n1, GaimBlistNode *n2) +{ + int ret; + + g_return_val_if_fail(n1->type == n2->type, -1); + + switch (n1->type) { + case GAIM_BLIST_CONTACT_NODE: + n1 = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)n1); + n2 = (GaimBlistNode*)gaim_contact_get_priority_buddy((GaimContact*)n2); + /* now compare the presence of the priority buddies */ + case GAIM_BLIST_BUDDY_NODE: + ret = gaim_presence_compare(gaim_buddy_get_presence((GaimBuddy*)n1), + gaim_buddy_get_presence((GaimBuddy*)n2)); + if (ret != 0) + return ret; + break; + default: + break; + } + + /* Sort alphabetically if presence is not comparable */ + ret = blist_node_compare_text(n1, n2); + + return ret; +} + +static int +get_contact_log_size(GaimBlistNode *c) +{ + int log = 0; + GaimBlistNode *node; + + for (node = c->child; node; node = node->next) { + GaimBuddy *b = (GaimBuddy*)node; + log += gaim_log_get_total_size(GAIM_LOG_IM, b->name, b->account); + } + + return log; +} + +static int +blist_node_compare_log(GaimBlistNode *n1, GaimBlistNode *n2) +{ + int ret; + GaimBuddy *b1, *b2; + + g_return_val_if_fail(n1->type == n2->type, -1); + + switch (n1->type) { + case GAIM_BLIST_BUDDY_NODE: + b1 = (GaimBuddy*)n1; + b2 = (GaimBuddy*)n2; + ret = gaim_log_get_total_size(GAIM_LOG_IM, b2->name, b2->account) - + gaim_log_get_total_size(GAIM_LOG_IM, b1->name, b1->account); + if (ret != 0) + return ret; + break; + case GAIM_BLIST_CONTACT_NODE: + ret = get_contact_log_size(n2) - get_contact_log_size(n1); + if (ret != 0) + return ret; + break; + default: + break; + } + ret = blist_node_compare_text(n1, n2); + return ret; +} + static gboolean blist_clicked(GntTree *tree, GntMouseEvent event, int x, int y, gpointer ggblist) { @@ -1678,27 +1768,19 @@ action->callback(action); } -static void -reconstruct_accounts_menu() +static GntMenuItem *reconstruct_accounts_menu() { - GntWidget *menu, *sub; - GntMenuItem *item; - GntWindow *window; + GntWidget *sub; + GntMenuItem *acc, *item; GList *iter; if (!ggblist) - return; - - window = GNT_WINDOW(ggblist->window); + return NULL; - menu = gnt_menu_new(GNT_MENU_TOPLEVEL); - gnt_window_set_menu(window, GNT_MENU(menu)); - - item = gnt_menuitem_new(_("Accounts")); - gnt_menu_add_item(GNT_MENU(menu), item); + acc = gnt_menuitem_new(_("Accounts")); sub = gnt_menu_new(GNT_MENU_POPUP); - gnt_menuitem_set_submenu(item, GNT_MENU(sub)); + gnt_menuitem_set_submenu(acc, GNT_MENU(sub)); for (iter = gaim_accounts_get_all_active(); iter; iter = g_list_delete_link(iter, iter)) { @@ -1737,6 +1819,58 @@ } } } + return acc; +} + +static void show_offline_cb(GntMenuItem *item, gpointer n) +{ + gaim_prefs_set_bool(PREF_ROOT "/showoffline", + !gaim_prefs_get_bool(PREF_ROOT "/showoffline")); +} + +static void sort_blist_change_cb(GntMenuItem *item, gpointer n) +{ + gaim_prefs_set_string(PREF_ROOT "/sort_type", n); +} + +static void +create_menu() +{ + GntWidget *menu, *sub; + GntMenuItem *item; + GntWindow *window; + + if (!ggblist) + return; + + window = GNT_WINDOW(ggblist->window); + menu = gnt_menu_new(GNT_MENU_TOPLEVEL); + gnt_window_set_menu(window, GNT_MENU(menu)); + + item = gnt_menuitem_new(_("Options")); + gnt_menu_add_item(GNT_MENU(menu), item); + + sub = gnt_menu_new(GNT_MENU_POPUP); + gnt_menuitem_set_submenu(item, GNT_MENU(sub)); + + item = gnt_menuitem_new(_("Toggle offline buddies")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), show_offline_cb, NULL); + + item = gnt_menuitem_new(_("Sort by status")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "status"); + + item = gnt_menuitem_new(_("Sort alphabetically")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "text"); + + item = gnt_menuitem_new(_("Sort by log size")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(GNT_MENUITEM(item), sort_blist_change_cb, "log"); + + item = reconstruct_accounts_menu(); + gnt_menu_add_item(GNT_MENU(menu), item); } void gg_blist_show() @@ -1755,7 +1889,7 @@ gnt_box_set_pad(GNT_BOX(ggblist->window), 0); ggblist->tree = gnt_tree_new(); - gnt_tree_set_compare_func(GNT_TREE(ggblist->tree), (GCompareFunc)blist_node_compare); + GNT_WIDGET_SET_FLAGS(ggblist->tree, GNT_WIDGET_NO_BORDER); gnt_tree_set_col_width(GNT_TREE(ggblist->tree), 0, 25); gnt_widget_set_size(ggblist->tree, gaim_prefs_get_int(PREF_ROOT "/size/width"), @@ -1773,9 +1907,9 @@ gnt_widget_show(ggblist->window); gaim_signal_connect(gaim_connections_get_handle(), "signed-on", gg_blist_get_handle(), - GAIM_CALLBACK(reconstruct_accounts_menu), NULL); + GAIM_CALLBACK(create_menu), NULL); gaim_signal_connect(gaim_connections_get_handle(), "signed-off", gg_blist_get_handle(), - GAIM_CALLBACK(reconstruct_accounts_menu), NULL); + GAIM_CALLBACK(create_menu), NULL); gaim_signal_connect(gaim_blist_get_handle(), "buddy-status-changed", gg_blist_get_handle(), GAIM_CALLBACK(buddy_status_changed), ggblist); gaim_signal_connect(gaim_blist_get_handle(), "buddy-idle-changed", gg_blist_get_handle(), @@ -1817,7 +1951,7 @@ g_signal_connect(G_OBJECT(ggblist->statustext), "key_pressed", G_CALLBACK(status_text_changed), NULL); - reconstruct_accounts_menu(ggblist); + create_menu(); populate_buddylist(); diff -r 556a112ab6ca -r b15c2eaeb67f console/libgnt/gnttree.c --- a/console/libgnt/gnttree.c Thu Oct 12 02:51:52 2006 +0000 +++ b/console/libgnt/gnttree.c Thu Oct 12 03:26:33 2006 +0000 @@ -45,6 +45,18 @@ static GntWidgetClass *parent_class = NULL; static guint signals[SIGS] = { 0 }; +/* Move the item at position old to position new */ +static GList * +g_list_reposition_child(GList *list, int old, int new) +{ + gpointer item = g_list_nth_data(list, old); + list = g_list_remove(list, item); + if (old < new) + new--; /* because the positions would have shifted after removing the item */ + list = g_list_insert(list, item, new); + return list; +} + static GntTreeRow * _get_next(GntTreeRow *row, gboolean godeep) { @@ -837,6 +849,75 @@ return NULL; } +void gnt_tree_sort_row(GntTree *tree, gpointer key) +{ + GntTreeRow *row, *q, *s; + int current, newp; + + if (!tree->compare) + return; + + row = g_hash_table_lookup(tree->hash, key); + g_return_if_fail(row != NULL); + + current = g_list_index(tree->list, key); + + if (row->parent) + s = row->parent->child; + else + s = tree->root; + + q = NULL; + while (s) { + if (tree->compare(row->key, s->key) < 0) + break; + q = s; + s = s->next; + } + + /* Move row between q and s */ + if (row == q || row == s) + return; + + if (q == NULL) { + /* row becomes the first child of its parent */ + row->prev->next = row->next; /* row->prev cannot be NULL at this point */ + if (row->next) + row->next->prev = row->prev; + if (row->parent) + row->parent->child = row; + else + tree->root = row; + row->next = s; + s->prev = row; /* s cannot be NULL */ + row->prev = NULL; + newp = g_list_index(tree->list, s) - 1; + } else { + if (row->prev) { + row->prev->next = row->next; + } else { + /* row was the first child of its parent */ + if (row->parent) + row->parent->child = row->next; + else + tree->top = row->next; + } + + if (row->next) + row->next->prev = row->prev; + + q->next = row; + row->prev = q; + if (s) + s->prev = row; + row->next = s; + newp = g_list_index(tree->list, q) + 1; + } + tree->list = g_list_reposition_child(tree->list, current, newp); + + redraw_tree(tree); +} + GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) { GntTreeRow *pr = NULL; diff -r 556a112ab6ca -r b15c2eaeb67f console/libgnt/gnttree.h --- a/console/libgnt/gnttree.h Thu Oct 12 02:51:52 2006 +0000 +++ b/console/libgnt/gnttree.h Thu Oct 12 03:26:33 2006 +0000 @@ -123,6 +123,8 @@ void gnt_tree_set_show_separator(GntTree *tree, gboolean set); +void gnt_tree_sort_row(GntTree *tree, void *row); + /* This will try to automatically adjust the width of the columns in the tree */ void gnt_tree_adjust_columns(GntTree *tree);