finch/plugins/grouping/grouping.c

changeset 41704
f25917ae8556
parent 41078
84e48180ef67
child 41733
a9085b52de8b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/plugins/grouping/grouping.c	Mon Sep 19 04:29:45 2022 -0500
@@ -0,0 +1,394 @@
+/**
+ * Copyright (C) 2008 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA
+ */
+
+#include <glib/gi18n-lib.h>
+
+#include <purple.h>
+
+#include <gnt.h>
+
+#include <finch.h>
+
+
+#define FINCH_TYPE_GROUPING_NODE     (finch_grouping_node_get_type())
+#define FINCH_GROUPING_NODE(obj)     (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_GROUPING_NODE, FinchGroupingNode))
+#define FINCH_IS_GROUPING_NODE(obj)  (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_GROUPING_NODE))
+
+typedef struct {
+	PurpleBlistNode node;
+} FinchGroupingNode;
+
+typedef struct {
+	PurpleBlistNodeClass node_class;
+} FinchGroupingNodeClass;
+
+static FinchBlistManager *default_manager;
+
+/**
+ * GObject code
+ */
+static void
+finch_grouping_node_init(G_GNUC_UNUSED FinchGroupingNode *node)
+{
+}
+
+static void
+finch_grouping_node_class_init(G_GNUC_UNUSED FinchGroupingNodeClass *klass)
+{
+}
+
+static void
+finch_grouping_node_class_finalize(G_GNUC_UNUSED FinchGroupingNodeClass *klass)
+{
+}
+
+GType finch_grouping_node_get_type(void);
+G_DEFINE_DYNAMIC_TYPE(FinchGroupingNode, finch_grouping_node,
+                      PURPLE_TYPE_BLIST_NODE);
+
+/**
+ * Online/Offline
+ */
+static FinchGroupingNode *online, *offline;
+
+static gboolean on_offline_init()
+{
+	GntTree *tree = finch_blist_get_tree();
+
+	gnt_tree_add_row_after(tree, online,
+			gnt_tree_create_row(tree, _("Online")), NULL, NULL);
+	gnt_tree_add_row_after(tree, offline,
+			gnt_tree_create_row(tree, _("Offline")), NULL, online);
+
+	return TRUE;
+}
+
+static gboolean on_offline_can_add_node(PurpleBlistNode *node)
+{
+	if (PURPLE_IS_CONTACT(node)) {
+		PurpleContact *contact = PURPLE_CONTACT(node);
+		if (purple_counting_node_get_current_size(PURPLE_COUNTING_NODE(contact)) > 0)
+			return TRUE;
+		return FALSE;
+	} else if (PURPLE_IS_BUDDY(node)) {
+		PurpleBuddy *buddy = PURPLE_BUDDY(node);
+		if (PURPLE_BUDDY_IS_ONLINE(buddy))
+			return TRUE;
+		if (purple_prefs_get_bool("/finch/blist/showoffline") &&
+				purple_account_is_connected(purple_buddy_get_account(buddy)))
+			return TRUE;
+		return FALSE;
+	} else if (PURPLE_IS_CHAT(node)) {
+		PurpleChat *chat = PURPLE_CHAT(node);
+		return purple_account_is_connected(purple_chat_get_account(chat));
+	}
+
+	return FALSE;
+}
+
+static gpointer on_offline_find_parent(PurpleBlistNode *node)
+{
+	gpointer ret = NULL;
+
+	if (PURPLE_IS_CONTACT(node)) {
+		node = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)));
+		ret = PURPLE_BUDDY_IS_ONLINE(PURPLE_BUDDY(node)) ? online : offline;
+	} else if (PURPLE_IS_BUDDY(node)) {
+		ret = purple_blist_node_get_parent(node);
+		finch_blist_manager_add_node(ret);
+	} else if (PURPLE_IS_CHAT(node)) {
+		ret = online;
+	}
+
+	return ret;
+}
+
+static gboolean on_offline_create_tooltip(gpointer selected_row, GString **body, char **tool_title)
+{
+	PurpleBlistNode *node = selected_row;
+
+	if (FINCH_IS_GROUPING_NODE(node)) {
+		/* There should be some easy way of getting the total online count,
+		 * or total number of chats. Doing a loop here will probably be pretty
+		 * expensive. */
+		if (body)
+			*body = g_string_new(FINCH_GROUPING_NODE(node) == online ?
+					_("Online Buddies") : _("Offline Buddies"));
+		return TRUE;
+	} else {
+		return default_manager ? default_manager->create_tooltip(selected_row, body, tool_title) : FALSE;
+	}
+}
+
+static FinchBlistManager on_offline =
+{
+	"on-offline",
+	N_("Online/Offline"),
+	on_offline_init,
+	NULL,
+	on_offline_can_add_node,
+	on_offline_find_parent,
+	on_offline_create_tooltip,
+	{NULL, NULL, NULL, NULL}
+};
+
+/**
+ * Meebo-like Grouping.
+ */
+static FinchGroupingNode meebo;
+static gboolean meebo_init()
+{
+	GntTree *tree = finch_blist_get_tree();
+	if (!g_list_find(gnt_tree_get_rows(tree), &meebo)) {
+		gnt_tree_add_row_last(tree, &meebo,
+				gnt_tree_create_row(tree, _("Offline")), NULL);
+	}
+	return TRUE;
+}
+
+static gpointer meebo_find_parent(PurpleBlistNode *node)
+{
+	if (PURPLE_IS_CONTACT(node)) {
+		PurpleBuddy *buddy = purple_contact_get_priority_buddy(PURPLE_CONTACT(node));
+		if (buddy && !PURPLE_BUDDY_IS_ONLINE(buddy)) {
+			return &meebo;
+		}
+	}
+	return default_manager->find_parent(node);
+}
+
+static FinchBlistManager meebo_group =
+{
+	"meebo",
+	N_("Meebo"),
+	meebo_init,
+	NULL,
+	NULL,
+	meebo_find_parent,
+	NULL,
+	{NULL, NULL, NULL, NULL}
+};
+
+/**
+ * No Grouping.
+ */
+static gboolean no_group_init()
+{
+	GntTree *tree = finch_blist_get_tree();
+	g_object_set(G_OBJECT(tree), "expander-level", 0, NULL);
+	return TRUE;
+}
+
+static gboolean no_group_uninit()
+{
+	GntTree *tree = finch_blist_get_tree();
+	g_object_set(G_OBJECT(tree), "expander-level", 1, NULL);
+	return TRUE;
+}
+
+static gboolean no_group_can_add_node(PurpleBlistNode *node)
+{
+	return on_offline_can_add_node(node);   /* These happen to be the same */
+}
+
+static gpointer no_group_find_parent(PurpleBlistNode *node)
+{
+	gpointer ret = NULL;
+
+	if (PURPLE_IS_BUDDY(node)) {
+		ret = purple_blist_node_get_parent(node);
+		finch_blist_manager_add_node(ret);
+	}
+
+	return ret;
+}
+
+static FinchBlistManager no_group =
+{
+	"no-group",
+	N_("No Grouping"),
+	no_group_init,
+	no_group_uninit,
+	no_group_can_add_node,
+	no_group_find_parent,
+	NULL,
+	{NULL, NULL, NULL, NULL}
+};
+
+/**
+ * Nested Grouping
+ */
+static GHashTable *groups;
+
+static gboolean
+nested_group_init(void)
+{
+	groups = g_hash_table_new_full(g_str_hash, g_str_equal,
+			g_free, g_free);
+	return TRUE;
+}
+
+static gboolean
+nested_group_uninit(void)
+{
+	g_hash_table_destroy(groups);
+	groups = NULL;
+	return TRUE;
+}
+
+static gpointer
+nested_group_find_parent(PurpleBlistNode *node)
+{
+	char *name;
+	PurpleGroup *group;
+	char *sep;
+	PurpleBlistNode *ret, *parent;
+	GntTree *tree;
+
+	if (!PURPLE_IS_GROUP(node))
+		return default_manager->find_parent(node);
+
+	group = PURPLE_GROUP(node);
+	name = g_strdup(purple_group_get_name(group));
+	if (!(sep = strchr(name, '/'))) {
+		g_free(name);
+		return default_manager->find_parent(node);
+	}
+
+	tree = finch_blist_get_tree();
+	parent = NULL;
+
+	while (sep) {
+		*sep = 0;
+		if (*(sep + 1) && (ret = PURPLE_BLIST_NODE(purple_blist_find_group(name)))) {
+			finch_blist_manager_add_node(ret);
+			parent = ret;
+		} else if (!(ret = g_hash_table_lookup(groups, name))) {
+			ret = g_object_new(FINCH_TYPE_GROUPING_NODE, NULL);
+			g_hash_table_insert(groups, g_strdup(name), ret);
+			gnt_tree_add_row_last(tree, ret,
+					gnt_tree_create_row(tree, name), parent);
+			parent = ret;
+		}
+		*sep = '/';
+		sep = strchr(sep + 1, '/');
+	}
+
+	g_free(name);
+	return ret;
+}
+
+static gboolean
+nested_group_create_tooltip(gpointer selected_row, GString **body, char **title)
+{
+	PurpleBlistNode *node = selected_row;
+	if (!FINCH_IS_GROUPING_NODE(node)) {
+		return default_manager->create_tooltip(selected_row, body, title);
+	}
+	if (body)
+		*body = g_string_new(_("Nested Subgroup"));  /* Perhaps list the child groups/subgroups? */
+	return TRUE;
+}
+
+static gboolean
+nested_group_can_add_node(PurpleBlistNode *node)
+{
+	PurpleBlistNode *group;
+	int len;
+
+	if (!PURPLE_IS_GROUP(node))
+		return default_manager->can_add_node(node);
+
+	if (default_manager->can_add_node(node))
+		return TRUE;
+
+	len = strlen(purple_group_get_name(PURPLE_GROUP(node)));
+	group = purple_blist_get_default_root();
+	for (; group; group = purple_blist_node_get_sibling_next(group)) {
+		if (group == node)
+			continue;
+		if (strncmp(purple_group_get_name(PURPLE_GROUP(node)),
+					purple_group_get_name(PURPLE_GROUP(group)), len) == 0 &&
+				default_manager->can_add_node(group))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+static FinchBlistManager nested_group =
+{
+	"nested",
+	N_("Nested Grouping (experimental)"),
+	.init = nested_group_init,
+	.uninit = nested_group_uninit,
+	.find_parent = nested_group_find_parent,
+	.create_tooltip = nested_group_create_tooltip,
+	.can_add_node = nested_group_can_add_node,
+};
+
+static GPluginPluginInfo *
+grouping_query(GError **error) {
+	const gchar * const authors[] = {
+		"Sadrul H Chowdhury <sadrul@users.sourceforge.net>",
+		NULL
+	};
+
+	return finch_plugin_info_new(
+		"id",           "grouping",
+		"name",         N_("Grouping"),
+		"version",      VERSION,
+		"category",     N_("User interface"),
+		"summary",      N_("Provides alternate buddylist grouping options."),
+		"description",  N_("Provides alternate buddylist grouping options."),
+		"authors",      authors,
+		"website",      PURPLE_WEBSITE,
+		"abi-version",  PURPLE_ABI_VERSION,
+		NULL
+	);
+}
+
+static gboolean
+grouping_load(GPluginPlugin *plugin, GError **error) {
+	finch_grouping_node_register_type(G_TYPE_MODULE(plugin));
+
+	default_manager = finch_blist_manager_find("default");
+
+	online  = g_object_new(FINCH_TYPE_GROUPING_NODE, NULL);
+	offline = g_object_new(FINCH_TYPE_GROUPING_NODE, NULL);
+
+	finch_blist_install_manager(&on_offline);
+	finch_blist_install_manager(&meebo_group);
+	finch_blist_install_manager(&no_group);
+	finch_blist_install_manager(&nested_group);
+	return TRUE;
+}
+
+static gboolean
+grouping_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) {
+	finch_blist_uninstall_manager(&on_offline);
+	finch_blist_uninstall_manager(&meebo_group);
+	finch_blist_uninstall_manager(&no_group);
+	finch_blist_uninstall_manager(&nested_group);
+
+	g_object_unref(online);
+	g_object_unref(offline);
+
+	return TRUE;
+}
+
+GPLUGIN_NATIVE_PLUGIN_DECLARE(grouping)

mercurial