comparison src/gtkblist.c @ 5422:af62169c74fd

[gaim-migrate @ 5801] Not to be too LSchieresque, but: <SeanEgan> Which should I do? Finish writing sorting code or commit sorting code? <Robot101> the latter, then the former. This is my incomplete buddy list sorting code. Sorting methods are modular, a plugin can add its own if it wanted to. Included are four sorting methods: None - this will be perceived as no sorting. It sorts the list in the order specified in blist.xml Alphabetical - duh. By status - this isn't really written yet, but I'm going to fix it right now. This will sort using idle time, away status, and online status when it's written By log file size - this puts the people you talk to the most at the top of your list. Pretty keen, eh? Of course this is replete with Sean Egan Hacks (TM). Now I'm going to go eat some weird "golden crunch" cereal from nestle. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Sun, 18 May 2003 03:41:31 +0000
parents ab1cb8b5e42b
children 04e1e40b99b0
comparison
equal deleted inserted replaced
5421:7955274fa92b 5422:af62169c74fd
29 #endif /* GAIM_PLUGINS */ 29 #endif /* GAIM_PLUGINS */
30 #include <string.h> 30 #include <string.h>
31 #include <stdio.h> 31 #include <stdio.h>
32 #include <stdlib.h> 32 #include <stdlib.h>
33 #include <ctype.h> 33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
34 #include <math.h> 37 #include <math.h>
35 #include <time.h> 38 #include <time.h>
36 #include <ctype.h>
37 39
38 #ifdef _WIN32 40 #ifdef _WIN32
39 #include <gdk/gdkwin32.h> 41 #include <gdk/gdkwin32.h>
40 #else 42 #else
41 #include <unistd.h> 43 #include <unistd.h>
54 56
55 #ifdef _WIN32 57 #ifdef _WIN32
56 #include "win32dep.h" 58 #include "win32dep.h"
57 #endif 59 #endif
58 60
61 GSList *gaim_gtk_blist_sort_methods = NULL;
62 static struct gaim_gtk_blist_sort_method *current_sort_method = NULL;
63 static GtkTreeIter sort_method_none(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
64 static GtkTreeIter sort_method_alphabetical(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
65 static GtkTreeIter sort_method_status(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
66 static GtkTreeIter sort_method_log(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
59 static struct gaim_gtk_buddy_list *gtkblist = NULL; 67 static struct gaim_gtk_buddy_list *gtkblist = NULL;
60 68
61 /* part of the best damn Docklet code this side of Tahiti */ 69 /* part of the best damn Docklet code this side of Tahiti */
62 static gboolean gaim_gtk_blist_obscured = FALSE; 70 static gboolean gaim_gtk_blist_obscured = FALSE;
63 71
64 static void gaim_gtk_blist_selection_changed(GtkTreeSelection *selection, gpointer data); 72 static void gaim_gtk_blist_selection_changed(GtkTreeSelection *selection, gpointer data);
65 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node); 73 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node);
66 static char *gaim_get_tooltip_text(GaimBlistNode *node); 74 static char *gaim_get_tooltip_text(GaimBlistNode *node);
67 static char *item_factory_translate_func (const char *path, gpointer func_data); 75 static char *item_factory_translate_func (const char *path, gpointer func_data);
68 static gboolean get_iter_from_node(GaimBlistNode *node, GtkTreeIter *iter); 76 static gboolean get_iter_from_node(GaimBlistNode *node, GtkTreeIter *iter);
77
78 char sort_method[64];
69 79
70 struct _gaim_gtk_blist_node { 80 struct _gaim_gtk_blist_node {
71 GtkTreeRowReference *row; 81 GtkTreeRowReference *row;
72 }; 82 };
73 83
1305 item_factory_translate_func (const char *path, gpointer func_data) 1315 item_factory_translate_func (const char *path, gpointer func_data)
1306 { 1316 {
1307 return _(path); 1317 return _(path);
1308 } 1318 }
1309 1319
1320 void gaim_gtk_blist_setup_sort_methods()
1321 {
1322 gaim_gtk_blist_sort_method_reg("None", sort_method_none);
1323 gaim_gtk_blist_sort_method_reg("Alphabetical", sort_method_alphabetical);
1324 gaim_gtk_blist_sort_method_reg("By status", sort_method_status);
1325 gaim_gtk_blist_sort_method_reg("By log size", sort_method_log);
1326 gaim_gtk_blist_sort_method_set(sort_method[0] ? sort_method : "None");
1327 }
1328
1329
1310 static void gaim_gtk_blist_show(struct gaim_buddy_list *list) 1330 static void gaim_gtk_blist_show(struct gaim_buddy_list *list)
1311 { 1331 {
1312 GtkItemFactory *ift; 1332 GtkItemFactory *ift;
1313 GtkCellRenderer *rend; 1333 GtkCellRenderer *rend;
1314 GtkTreeViewColumn *column; 1334 GtkTreeViewColumn *column;
1502 /* start the refresh timer */ 1522 /* start the refresh timer */
1503 if (blist_options & (OPT_BLIST_SHOW_IDLETIME | OPT_BLIST_SHOW_ICONS)) 1523 if (blist_options & (OPT_BLIST_SHOW_IDLETIME | OPT_BLIST_SHOW_ICONS))
1504 gtkblist->refresh_timer = g_timeout_add(30000, (GSourceFunc)gaim_gtk_blist_refresh_timer, list); 1524 gtkblist->refresh_timer = g_timeout_add(30000, (GSourceFunc)gaim_gtk_blist_refresh_timer, list);
1505 } 1525 }
1506 1526
1507 void gaim_gtk_blist_refresh(struct gaim_buddy_list *list) 1527 static void redo_buddy_list(struct gaim_buddy_list *list, gboolean remove)
1508 { 1528 {
1509 GaimBlistNode *group, *buddy; 1529 GaimBlistNode *group, *buddy;
1510 1530
1511 for(group = list->root; group; group = group->next) { 1531 for(group = list->root; group; group = group->next) {
1512 if(!GAIM_BLIST_NODE_IS_GROUP(group)) 1532 if(!GAIM_BLIST_NODE_IS_GROUP(group))
1513 continue; 1533 continue;
1514 gaim_gtk_blist_update(list, group); 1534 gaim_gtk_blist_update(list, group);
1515 for(buddy = group->child; buddy; buddy = buddy->next) { 1535 for(buddy = group->child; buddy; buddy = buddy->next) {
1536 if (remove)
1537 gaim_gtk_blist_hide_node(list, buddy);
1516 gaim_gtk_blist_update(list, buddy); 1538 gaim_gtk_blist_update(list, buddy);
1517 } 1539 }
1518 } 1540 }
1541 }
1542
1543 void gaim_gtk_blist_refresh(struct gaim_buddy_list *list)
1544 {
1545 redo_buddy_list(list, FALSE);
1519 } 1546 }
1520 1547
1521 void 1548 void
1522 gaim_gtk_blist_update_refresh_timeout() 1549 gaim_gtk_blist_update_refresh_timeout()
1523 { 1550 {
1674 NODE_COLUMN, node, 1701 NODE_COLUMN, node,
1675 -1); 1702 -1);
1676 g_free(mark); 1703 g_free(mark);
1677 } 1704 }
1678 1705
1679
1680 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node) 1706 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node)
1681 { 1707 {
1682 GtkTreeIter iter; 1708 GtkTreeIter iter;
1683 GtkTreePath *expand = NULL, *newpath = NULL; 1709 GtkTreePath *expand = NULL, *newpath = NULL;
1684 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data; 1710 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
1704 } 1730 }
1705 if(!collapsed) 1731 if(!collapsed)
1706 expand = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter); 1732 expand = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter);
1707 else 1733 else
1708 g_free(collapsed); 1734 g_free(collapsed);
1709 1735
1710 oldersibling = node->prev; 1736 iter = current_sort_method->func(node, list, groupiter, NULL);
1711 while (oldersibling && !get_iter_from_node(oldersibling, &oldersiblingiter)) { 1737
1712 oldersibling = oldersibling->prev;
1713 }
1714
1715 gtk_tree_store_insert_after(gtkblist->treemodel, &iter, &groupiter, oldersibling ? &oldersiblingiter : NULL);
1716 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
1717 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
1718 gtk_tree_path_free(newpath);
1719
1720 if (blist_options & OPT_BLIST_POPUP) { 1738 if (blist_options & OPT_BLIST_POPUP) {
1721 gtk_widget_show(gtkblist->window); 1739 gtk_widget_show(gtkblist->window);
1722 gtk_window_deiconify(GTK_WINDOW(gtkblist->window)); 1740 gtk_window_deiconify(GTK_WINDOW(gtkblist->window));
1723 gdk_window_raise(gtkblist->window->window); 1741 gdk_window_raise(gtkblist->window->window);
1724 } 1742 }
1814 g_object_unref(status); 1832 g_object_unref(status);
1815 } else if(GAIM_BLIST_NODE_IS_CHAT(node) && !((struct chat *)node)->account->gc) { 1833 } else if(GAIM_BLIST_NODE_IS_CHAT(node) && !((struct chat *)node)->account->gc) {
1816 gaim_gtk_blist_hide_node(list, node); 1834 gaim_gtk_blist_hide_node(list, node);
1817 } else if (GAIM_BLIST_NODE_IS_BUDDY(node) && (((struct buddy*)node)->present != GAIM_BUDDY_OFFLINE || ((blist_options & OPT_BLIST_SHOW_OFFLINE) && ((struct buddy*)node)->account->gc))) { 1835 } else if (GAIM_BLIST_NODE_IS_BUDDY(node) && (((struct buddy*)node)->present != GAIM_BUDDY_OFFLINE || ((blist_options & OPT_BLIST_SHOW_OFFLINE) && ((struct buddy*)node)->account->gc))) {
1818 GdkPixbuf *status, *avatar; 1836 GdkPixbuf *status, *avatar;
1837 GtkTreeIter groupiter;
1819 char *mark; 1838 char *mark;
1820 char *warning = NULL, *idle = NULL; 1839 char *warning = NULL, *idle = NULL;
1821 1840
1822 gboolean selected = (gtkblist->selected_node == node); 1841 gboolean selected = (gtkblist->selected_node == node);
1823 1842
1855 char *i2 = g_strdup_printf("<span color='dim grey'>%s</span>", 1874 char *i2 = g_strdup_printf("<span color='dim grey'>%s</span>",
1856 idle); 1875 idle);
1857 g_free(idle); 1876 g_free(idle);
1858 idle = i2; 1877 idle = i2;
1859 } 1878 }
1879 }
1880 if (!selected) {
1881 get_iter_from_node(node->parent, &groupiter);
1882 iter = current_sort_method->func(node, list, groupiter, &iter);
1860 } 1883 }
1861 1884
1862 gtk_tree_store_set(gtkblist->treemodel, &iter, 1885 gtk_tree_store_set(gtkblist->treemodel, &iter,
1863 STATUS_ICON_COLUMN, status, 1886 STATUS_ICON_COLUMN, status,
1864 STATUS_ICON_VISIBLE_COLUMN, TRUE, 1887 STATUS_ICON_VISIBLE_COLUMN, TRUE,
2066 g_free(filename); 2089 g_free(filename);
2067 2090
2068 return status; 2091 return status;
2069 } 2092 }
2070 2093
2094
2095 /*********************************************************************
2096 * Buddy List sorting functions *
2097 *********************************************************************/
2098
2099 void gaim_gtk_blist_sort_method_reg(const char *name, gaim_gtk_blist_sort_function func)
2100 {
2101 struct gaim_gtk_blist_sort_method *method = g_new0(struct gaim_gtk_blist_sort_method, 1);
2102 method->name = g_strdup(name);
2103 method->func = func;
2104 gaim_gtk_blist_sort_methods = g_slist_append(gaim_gtk_blist_sort_methods, method);
2105 }
2106
2107 void gaim_gtk_blist_sort_method_unreg(const char *name){
2108
2109 }
2110
2111 void gaim_gtk_blist_sort_method_set(const char *name){
2112 GSList *l = gaim_gtk_blist_sort_methods;
2113 while (l && gaim_utf8_strcasecmp(((struct gaim_gtk_blist_sort_method*)l->data)->name, name))
2114 l = l->next;
2115
2116 if (l) {
2117 current_sort_method = l->data;
2118 strcpy(sort_method, ((struct gaim_gtk_blist_sort_method*)l->data)->name);
2119 } else if (!current_sort_method) {
2120 gaim_gtk_blist_sort_method_set("None");
2121 return;
2122 }
2123 save_prefs();
2124 redo_buddy_list(gaim_get_blist(), TRUE);
2125
2126 }
2127
2128 /******************************************
2129 ** Sort Methods
2130 ******************************************/
2131
2132 /* A sort method takes a core buddy list node, the buddy list it belongs in, the GtkTreeIter of its group and
2133 * the nodes own iter if it has one. It returns the iter the buddy list should use to represent this buddy, be
2134 * it a new iter, or an existing one. If it is a new iter, and cur is defined, the buddy list will probably want
2135 * to remove cur from the buddy list. */
2136 static GtkTreeIter sort_method_none(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
2137 {
2138 GtkTreePath *newpath;
2139 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
2140 GaimBlistNode *oldersibling = node->prev;
2141 GtkTreeIter iter, oldersiblingiter;
2142
2143 if (cur)
2144 return *cur;
2145
2146 while (oldersibling && !get_iter_from_node(oldersibling, &oldersiblingiter)) {
2147 oldersibling = oldersibling->prev;
2148 }
2149
2150 gtk_tree_store_insert_after(gtkblist->treemodel, &iter, &groupiter, oldersibling ? &oldersiblingiter : NULL);
2151 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2152 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2153 gtk_tree_path_free(newpath);
2154 return iter;
2155 }
2156
2157 static GtkTreeIter sort_method_alphabetical(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
2158 {
2159 GtkTreeIter more_z, iter;
2160 GaimBlistNode *n;
2161 GtkTreePath *newpath;
2162 GValue val = {0,};
2163 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
2164
2165 if (cur)
2166 return *cur;
2167
2168
2169 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) {
2170 gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0);
2171 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2172 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2173 gtk_tree_path_free(newpath);
2174 return iter;
2175 }
2176
2177 do {
2178 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
2179 n = g_value_get_pointer(&val);
2180
2181 if (GAIM_BLIST_NODE_IS_BUDDY(n) && gaim_utf8_strcasecmp(gaim_get_buddy_alias((struct buddy*)node),
2182 gaim_get_buddy_alias((struct buddy*)n)) < 0) {
2183 gtk_tree_store_insert_before(gtkblist->treemodel, &iter, &groupiter, &more_z);
2184 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2185 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2186 gtk_tree_path_free(newpath);
2187 return iter;
2188 }
2189 g_value_unset(&val);
2190 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
2191
2192 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter);
2193 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2194 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2195 gtk_tree_path_free(newpath);
2196 return iter;
2197 }
2198
2199 static GtkTreeIter sort_method_status(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
2200 {
2201 GtkTreeIter more_z, iter;
2202 GaimBlistNode *n;
2203 GtkTreePath *newpath, *expand;
2204 GValue val = {0,};
2205 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
2206 char *collapsed = gaim_group_get_setting((struct group *)node->parent, "collapsed");
2207 if(!collapsed)
2208 expand = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter);
2209 else
2210 g_free(collapsed);
2211
2212
2213 if (cur)
2214 gaim_gtk_blist_hide_node(blist, node);
2215
2216 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) {
2217 gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0);
2218 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2219 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2220 gtk_tree_path_free(newpath);
2221 if(expand) {
2222 gtk_tree_view_expand_row(GTK_TREE_VIEW(gtkblist->treeview), expand, TRUE);
2223 gtk_tree_path_free(expand);
2224 }
2225 return iter;
2226 }
2227
2228 do {
2229 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
2230 n = g_value_get_pointer(&val);
2231
2232 if (n && GAIM_BLIST_NODE_IS_BUDDY(n)) {
2233 struct buddy *new = (struct buddy*)node, *it = (struct buddy*)n;
2234 if (it->idle > new->idle)
2235 {
2236 printf("Inserting %s before %s\n", new->name, it->name);
2237 gtk_tree_store_insert_before(gtkblist->treemodel, &iter, &groupiter, &more_z);
2238 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2239 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2240 gtk_tree_path_free(newpath);
2241 return iter;
2242 }
2243 g_value_unset(&val);
2244 }
2245 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
2246
2247 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter);
2248 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2249 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2250 gtk_tree_path_free(newpath);
2251 return iter;
2252 }
2253
2254 static GtkTreeIter sort_method_log(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
2255 {
2256 GtkTreeIter more_z, iter;
2257 GaimBlistNode *n;
2258 GtkTreePath *newpath;
2259 GValue val = {0,};
2260 struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
2261 char *logname = g_strdup_printf("%s.log", normalize(((struct buddy*)node)->name));
2262 char *filename = g_build_filename(gaim_user_dir(), "logs", logname, NULL);
2263 struct stat st, st2;
2264
2265 if (cur)
2266 return *cur;
2267
2268 if (stat(filename, &st))
2269 st.st_size = 0;
2270 g_free(filename);
2271 g_free(logname);
2272
2273 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) {
2274 gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0);
2275 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2276 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2277 gtk_tree_path_free(newpath);
2278 return iter;
2279 }
2280
2281 do {
2282
2283 gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
2284 n = g_value_get_pointer(&val);
2285
2286 logname = g_strdup_printf("%s.log", normalize(((struct buddy*)n)->name));
2287 filename = g_build_filename(gaim_user_dir(), "logs", logname, NULL);
2288 if (stat(filename, &st2))
2289 st2.st_size = 0;
2290 g_free(filename);
2291 g_free(logname);
2292 if (GAIM_BLIST_NODE_IS_BUDDY(n) && st.st_size > st2.st_size) {
2293 gtk_tree_store_insert_before(gtkblist->treemodel, &iter, &groupiter, &more_z);
2294 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2295 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2296 gtk_tree_path_free(newpath);
2297 return iter;
2298 }
2299 g_value_unset(&val);
2300 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
2301
2302 gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter);
2303 newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
2304 gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
2305 gtk_tree_path_free(newpath);
2306 return iter;
2307 }