diff 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
line wrap: on
line diff
--- a/src/gtkblist.c	Sun May 18 02:50:49 2003 +0000
+++ b/src/gtkblist.c	Sun May 18 03:41:31 2003 +0000
@@ -31,9 +31,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <math.h>
 #include <time.h>
-#include <ctype.h>
 
 #ifdef _WIN32
 #include <gdk/gdkwin32.h>
@@ -56,6 +58,12 @@
 #include "win32dep.h"
 #endif
 
+GSList *gaim_gtk_blist_sort_methods = NULL;
+static struct gaim_gtk_blist_sort_method *current_sort_method = NULL;
+static GtkTreeIter sort_method_none(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
+static GtkTreeIter sort_method_alphabetical(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
+static GtkTreeIter sort_method_status(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
+static GtkTreeIter sort_method_log(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
 static struct gaim_gtk_buddy_list *gtkblist = NULL;
 
 /* part of the best damn Docklet code this side of Tahiti */
@@ -67,6 +75,8 @@
 static char *item_factory_translate_func (const char *path, gpointer func_data);
 static gboolean get_iter_from_node(GaimBlistNode *node, GtkTreeIter *iter);
 
+char sort_method[64];
+
 struct _gaim_gtk_blist_node {
 	GtkTreeRowReference *row;
 };
@@ -1307,6 +1317,16 @@
 	return _(path);
 }
 
+void gaim_gtk_blist_setup_sort_methods()
+{
+	gaim_gtk_blist_sort_method_reg("None", sort_method_none);
+	gaim_gtk_blist_sort_method_reg("Alphabetical", sort_method_alphabetical);
+	gaim_gtk_blist_sort_method_reg("By status", sort_method_status);
+	gaim_gtk_blist_sort_method_reg("By log size", sort_method_log);
+	gaim_gtk_blist_sort_method_set(sort_method[0] ? sort_method : "None");
+}		
+
+
 static void gaim_gtk_blist_show(struct gaim_buddy_list *list)
 {
 	GtkItemFactory *ift;
@@ -1504,20 +1524,27 @@
 		gtkblist->refresh_timer = g_timeout_add(30000, (GSourceFunc)gaim_gtk_blist_refresh_timer, list);
 }
 
-void gaim_gtk_blist_refresh(struct gaim_buddy_list *list)
+static void redo_buddy_list(struct gaim_buddy_list *list, gboolean remove)
 {
 	GaimBlistNode *group, *buddy;
-
+	
 	for(group = list->root; group; group = group->next) {
 		if(!GAIM_BLIST_NODE_IS_GROUP(group))
 			continue;
 		gaim_gtk_blist_update(list, group);
 		for(buddy = group->child; buddy; buddy = buddy->next) {
+			if (remove)
+				gaim_gtk_blist_hide_node(list, buddy);
 			gaim_gtk_blist_update(list, buddy);
 		}
 	}
 }
 
+void gaim_gtk_blist_refresh(struct gaim_buddy_list *list)
+{
+	redo_buddy_list(list, FALSE);
+}
+
 void
 gaim_gtk_blist_update_refresh_timeout()
 {
@@ -1676,7 +1703,6 @@
 	g_free(mark);
 }
 
-
 static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node)
 {
 	GtkTreeIter iter;
@@ -1706,17 +1732,9 @@
 					expand = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter);
 				else
 					g_free(collapsed);
-
-				oldersibling = node->prev;
-				while (oldersibling && !get_iter_from_node(oldersibling, &oldersiblingiter)) {
-					oldersibling = oldersibling->prev;
-				}
-
-				gtk_tree_store_insert_after(gtkblist->treemodel, &iter, &groupiter, oldersibling ? &oldersiblingiter : NULL);
-				newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
-				gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
-				gtk_tree_path_free(newpath);
-
+				
+				iter = current_sort_method->func(node, list, groupiter, NULL);
+			
 				if (blist_options & OPT_BLIST_POPUP) {
 					gtk_widget_show(gtkblist->window);
 					gtk_window_deiconify(GTK_WINDOW(gtkblist->window));
@@ -1816,6 +1834,7 @@
 		gaim_gtk_blist_hide_node(list, node);
 	} 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))) {
 		GdkPixbuf *status, *avatar;
+		GtkTreeIter groupiter;
 		char *mark;
 		char *warning = NULL, *idle = NULL;
 
@@ -1858,6 +1877,10 @@
 				idle = i2;
 			}
 		}
+		if (!selected) {
+			get_iter_from_node(node->parent, &groupiter);
+			iter = current_sort_method->func(node, list, groupiter, &iter);
+		}
 
 		gtk_tree_store_set(gtkblist->treemodel, &iter,
 				   STATUS_ICON_COLUMN, status,
@@ -2068,3 +2091,217 @@
 	return status;
 }
 
+
+/*********************************************************************
+ * Buddy List sorting functions                                          *
+ *********************************************************************/
+
+void gaim_gtk_blist_sort_method_reg(const char *name, gaim_gtk_blist_sort_function func)
+{
+	struct gaim_gtk_blist_sort_method *method = g_new0(struct gaim_gtk_blist_sort_method, 1);
+	method->name = g_strdup(name);
+	method->func = func;
+	gaim_gtk_blist_sort_methods = g_slist_append(gaim_gtk_blist_sort_methods, method);
+}
+
+void gaim_gtk_blist_sort_method_unreg(const char *name){
+
+}
+
+void gaim_gtk_blist_sort_method_set(const char *name){
+	GSList *l = gaim_gtk_blist_sort_methods;
+	while (l && gaim_utf8_strcasecmp(((struct gaim_gtk_blist_sort_method*)l->data)->name, name))
+		l = l->next;
+	
+	if (l) {
+		current_sort_method = l->data;
+		strcpy(sort_method, ((struct gaim_gtk_blist_sort_method*)l->data)->name);
+	} else if (!current_sort_method) {
+		gaim_gtk_blist_sort_method_set("None");
+		return;
+	}
+	save_prefs();
+	redo_buddy_list(gaim_get_blist(), TRUE);
+
+}
+
+/******************************************
+ ** Sort Methods
+ ******************************************/
+
+/* A sort method takes a core buddy list node, the buddy list it belongs in, the GtkTreeIter of its group and
+ * the nodes own iter if it has one.  It returns the iter the buddy list should use to represent this buddy, be
+ * it a new iter, or an existing one.  If it is a new iter, and cur is defined, the buddy list will probably want
+ * to remove cur from the buddy list. */
+static GtkTreeIter sort_method_none(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
+{
+	GtkTreePath *newpath;
+	struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
+	GaimBlistNode *oldersibling = node->prev;
+	GtkTreeIter iter, oldersiblingiter;
+	
+	if (cur)
+		return *cur;
+	
+	while (oldersibling && !get_iter_from_node(oldersibling, &oldersiblingiter)) {
+		oldersibling = oldersibling->prev;
+	}
+	
+	gtk_tree_store_insert_after(gtkblist->treemodel, &iter, &groupiter, oldersibling ? &oldersiblingiter : NULL);
+	newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+	gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+	gtk_tree_path_free(newpath);
+	return iter;
+}
+
+static GtkTreeIter sort_method_alphabetical(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
+{
+	GtkTreeIter more_z, iter;
+	GaimBlistNode *n;
+	GtkTreePath *newpath;
+	GValue val = {0,};
+	struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
+
+	if (cur) 
+		return *cur;
+	
+
+	if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) {
+		gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0);
+		newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+		gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+		gtk_tree_path_free(newpath);
+		return iter;
+	}
+
+	do {
+		gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
+		n = g_value_get_pointer(&val);
+		
+		if (GAIM_BLIST_NODE_IS_BUDDY(n) && gaim_utf8_strcasecmp(gaim_get_buddy_alias((struct buddy*)node), 
+									gaim_get_buddy_alias((struct buddy*)n)) < 0) {
+			gtk_tree_store_insert_before(gtkblist->treemodel, &iter, &groupiter, &more_z);
+			newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+			gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+			gtk_tree_path_free(newpath);
+			return iter;
+		}
+		g_value_unset(&val);
+	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
+													  
+	gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter);
+	newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+	gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+	gtk_tree_path_free(newpath);
+	return iter;
+}
+
+static GtkTreeIter sort_method_status(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
+{
+	GtkTreeIter more_z, iter;
+	GaimBlistNode *n;
+	GtkTreePath *newpath, *expand;
+	GValue val = {0,};
+	struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
+	char *collapsed = gaim_group_get_setting((struct group *)node->parent, "collapsed");
+	if(!collapsed)
+		expand = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter);
+	else
+		g_free(collapsed);
+	
+	
+	if (cur)
+		gaim_gtk_blist_hide_node(blist, node);
+	
+	if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) {
+		gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0);
+		newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+		gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+		gtk_tree_path_free(newpath);
+		if(expand) {
+			gtk_tree_view_expand_row(GTK_TREE_VIEW(gtkblist->treeview), expand, TRUE);
+			gtk_tree_path_free(expand);
+		}
+		return iter;
+	}
+
+	do {
+		gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
+		n = g_value_get_pointer(&val);
+		
+		if (n && GAIM_BLIST_NODE_IS_BUDDY(n)) {
+			struct buddy *new = (struct buddy*)node, *it = (struct buddy*)n;
+			if (it->idle > new->idle)
+				{
+					printf("Inserting %s before %s\n", new->name, it->name);
+					gtk_tree_store_insert_before(gtkblist->treemodel, &iter, &groupiter, &more_z);
+						newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+						gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+						gtk_tree_path_free(newpath);
+						return iter;
+				}
+			g_value_unset(&val);
+		}
+	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
+
+	gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter);
+	newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+	gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+	gtk_tree_path_free(newpath);
+	return iter;
+}
+
+static GtkTreeIter sort_method_log(GaimBlistNode *node, struct gaim_buddy_list *blist, GtkTreeIter groupiter, GtkTreeIter *cur)
+{
+	GtkTreeIter more_z, iter;
+	GaimBlistNode *n;
+	GtkTreePath *newpath;
+	GValue val = {0,};
+	struct _gaim_gtk_blist_node *gtknode = (struct _gaim_gtk_blist_node *)node->ui_data;
+	char *logname = g_strdup_printf("%s.log", normalize(((struct buddy*)node)->name));
+	char *filename = g_build_filename(gaim_user_dir(), "logs", logname, NULL);
+	struct stat st, st2;
+	
+	if (cur)
+		return *cur;
+
+	if (stat(filename, &st))
+		st.st_size = 0;
+	g_free(filename);
+	g_free(logname);	
+
+	if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) {
+		gtk_tree_store_insert(gtkblist->treemodel, &iter, &groupiter, 0);
+		newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+		gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+		gtk_tree_path_free(newpath);
+		return iter;
+	}
+
+	do {
+		
+		gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
+		n = g_value_get_pointer(&val);
+		
+		logname = g_strdup_printf("%s.log", normalize(((struct buddy*)n)->name));
+		filename = g_build_filename(gaim_user_dir(), "logs", logname, NULL);
+		if (stat(filename, &st2))
+			st2.st_size = 0;
+		g_free(filename);
+		g_free(logname);
+		if (GAIM_BLIST_NODE_IS_BUDDY(n) && st.st_size > st2.st_size) {
+			gtk_tree_store_insert_before(gtkblist->treemodel, &iter, &groupiter, &more_z);
+			newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+			gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+			gtk_tree_path_free(newpath);
+			return iter;
+		}
+		g_value_unset(&val);
+	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
+													  
+	gtk_tree_store_append(gtkblist->treemodel, &iter, &groupiter);
+	newpath = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
+	gtknode->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(gtkblist->treemodel), newpath);
+	gtk_tree_path_free(newpath);
+	return iter;
+}