changeset 12688:473c23442a36

[gaim-migrate @ 15031] Add the notion of "popular" saved statuses. This lets us show 6 recently used/popular statuses in the context menu for the docklet. Eventually I'll add the same list to the status box--but that's a little more work. If someone else wants to tackle it before I have a chance to feel free (and let me know!) Does this look ok to everyone (the docklet menu changes)? Would it be better if it was a submenu? Or if it was labeled? It'd be cool if the icons reflected the status. Oh, and I just remembered that the menu items don't actually work yet... but that's not too hard, I think I can get to that tonight committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Tue, 03 Jan 2006 01:25:06 +0000
parents 88ccc3603163
children e893563d965d
files plugins/docklet/docklet.c src/savedstatuses.c src/savedstatuses.h
diffstat 3 files changed, 116 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/docklet/docklet.c	Tue Jan 03 01:19:32 2006 +0000
+++ b/plugins/docklet/docklet.c	Tue Jan 03 01:25:06 2006 +0000
@@ -367,6 +367,7 @@
 docklet_menu() {
 	static GtkWidget *menu = NULL;
 	GtkWidget *menuitem;
+	GList *popular_statuses, *cur;
 
 	if (menu) {
 		gtk_widget_destroy(menu);
@@ -409,6 +410,18 @@
 
 	gaim_separator(menu);
 
+	popular_statuses = gaim_savedstatuses_get_popular(6);
+	for (cur = popular_statuses; cur != NULL; cur = cur->next)
+	{
+		GaimSavedStatus *saved_status = cur->data;
+		gaim_new_item_from_stock(menu,
+			gaim_savedstatus_get_title(saved_status),
+			GAIM_STOCK_ICON_AWAY, NULL /* TODO */, NULL, 0, 0, NULL);
+	}
+	g_list_free(popular_statuses);
+
+	gaim_separator(menu);
+
 	gaim_new_item_from_stock(menu, _("Accounts"), GAIM_STOCK_ACCOUNTS, G_CALLBACK(gaim_gtk_accounts_window_show), NULL, 0, 0, NULL);
 	gaim_new_item_from_stock(menu, _("Plugins"), GAIM_STOCK_PLUGIN, G_CALLBACK(gaim_gtk_plugin_dialog_show), NULL, 0, 0, NULL);
 	gaim_new_item_from_stock(menu, _("Preferences"), GTK_STOCK_PREFERENCES, G_CALLBACK(gaim_gtk_prefs_show), NULL, 0, 0, NULL);
--- a/src/savedstatuses.c	Tue Jan 03 01:19:32 2006 +0000
+++ b/src/savedstatuses.c	Tue Jan 03 01:25:06 2006 +0000
@@ -60,6 +60,8 @@
 
 	time_t lastused;
 
+	unsigned int usage_count;
+
 	GList *substatuses;      /**< A list of GaimSavedStatusSub's. */
 };
 
@@ -75,6 +77,7 @@
 };
 
 static GList      *saved_statuses = NULL;
+static GList      *popular_statuses = NULL;
 static guint       save_timer = 0;
 static gboolean    statuses_loaded = FALSE;
 
@@ -272,6 +275,9 @@
 	snprintf(buf, sizeof(buf), "%lu", status->lastused);
 	xmlnode_set_attrib(node, "lastused", buf);
 
+	snprintf(buf, sizeof(buf), "%u", status->usage_count);
+	xmlnode_set_attrib(node, "usage_count", buf);
+
 	child = xmlnode_new_child(node, "state");
 	xmlnode_insert_data(child, gaim_primitive_get_id_from_type(status->type), -1);
 
@@ -458,6 +464,10 @@
 	attrib = xmlnode_get_attrib(status, "lastused");
 	ret->lastused = (attrib != NULL ? atol(attrib) : 0);
 
+	/* Read the usage count */
+	attrib = xmlnode_get_attrib(status, "usage_count");
+	ret->usage_count = (attrib != NULL ? atol(attrib) : 0);
+
 	/* Read the primitive status type */
 	node = xmlnode_get_child(status, "state");
 	if ((node != NULL) && ((data = xmlnode_get_data(node)) != NULL))
@@ -665,6 +675,50 @@
 	return saved_statuses;
 }
 
+/**
+ * A magic number is calcuated for each status, and then the
+ * statuses are ordered by the magic number.  The magic number
+ * is the date the status was last used offset by one day for
+ * each time the status has been used (but only by 10 days at
+ * the most).
+ *
+ * The goal is to have recently used statuses at the top of
+ * the list, but to also keep frequently used statuses near
+ * the top.
+ */
+static gint
+popular_statuses_compare_func(gconstpointer a, gconstpointer b)
+{
+	const GaimSavedStatus *saved_status_a = a;
+	const GaimSavedStatus *saved_status_b = b;
+	time_t time_a = saved_status_a->lastused +
+						(MIN(saved_status_a->usage_count, 10) * 86400);
+	time_t time_b = saved_status_b->lastused +
+						(MIN(saved_status_b->usage_count, 10) * 86400);
+	if (time_a > time_b)
+		return -1;
+	if (time_a < time_b)
+		return 1;
+	return 0;
+}
+
+GList *
+gaim_savedstatuses_get_popular(unsigned int how_many)
+{
+	GList *truncated = NULL;
+	GList *cur;
+	int i;
+
+	/* Copy 'how_many' elements to a new list */
+	for (i = 0, cur = popular_statuses; (i < how_many) && (cur != NULL); i++)
+	{
+		truncated = g_list_append(truncated, cur->data);
+		cur = cur->next;
+	}
+
+	return truncated;
+}
+
 GaimSavedStatus *
 gaim_savedstatus_get_current()
 {
@@ -747,6 +801,32 @@
 {
 	g_return_val_if_fail(saved_status != NULL, NULL);
 
+	/* If transient then make up a title on the fly */
+	if (saved_status->title == NULL)
+	{
+		const char *message = gaim_savedstatus_get_message(saved_status);
+
+		if (message == NULL)
+		{
+			GaimStatusPrimitive primitive;
+			primitive = gaim_savedstatus_get_type(saved_status);
+			return gaim_primitive_get_id_from_type(primitive);
+		}
+		else
+		{
+			static char buf[64];
+			strncpy(buf, message, sizeof(buf));
+			buf[sizeof(buf) - 1] = '\0';
+			if ((strlen(message) + 1) > sizeof(buf))
+			{
+				/* Truncate and ellipsize */
+				char *tmp = g_utf8_find_prev_char(buf, &buf[sizeof(buf) - 4]);
+				strcpy(tmp, "...");
+			}
+			return buf;
+		}
+	}
+
 	return saved_status->title;
 }
 
@@ -840,6 +920,14 @@
 	saved_status->lastused = time(NULL);
 	gaim_prefs_set_int("/core/savedstatus/current",
 					   gaim_savedstatus_get_creation_time(saved_status));
+
+	/* Update our list of popular statuses */
+	saved_status->usage_count++;
+	g_list_free(popular_statuses);
+	popular_statuses = g_list_copy(saved_statuses);
+	popular_statuses = g_list_sort(popular_statuses,
+		popular_statuses_compare_func);
+
 }
 
 void
--- a/src/savedstatuses.h	Tue Jan 03 01:19:32 2006 +0000
+++ b/src/savedstatuses.h	Tue Jan 03 01:25:06 2006 +0000
@@ -152,6 +152,21 @@
 const GList *gaim_savedstatuses_get_all(void);
 
 /**
+ * Returns the n most popular saved statuses.  "Popularity" is
+ * determined by when the last time a saved_status was used and
+ * how many times it has been used.
+ *
+ * @param how_many The maximum number of saved statuses
+ *                 to return, or '0' to get all saved
+ *                 statuses sorted by popularity.
+ * @return A linked list containing at most how_many
+ *         GaimSavedStatuses.  This list should be
+ *         g_list_free'd by the caller (but the
+ *         GaimSavedStatuses must not be free'd).
+ */
+GList *gaim_savedstatuses_get_popular(unsigned int how_many);
+
+/**
  * Returns the currently selected saved status.
  *
  * @return A pointer to the in-use GaimSavedStatus.