pidgin/pidgin

Port the room list from GtkTreeView to GtkColumnView

16 months ago, Elliott Sales de Andrade
941734e74261
Port the room list from GtkTreeView to GtkColumnView

Note, this removes the tooltip. It's not super easy to get the cell that the mouse is over, plus all it showed was the Name, which is pretty redundant.

It also removes the popup menu, for the same reason, as it just duplicates the response buttons, and on a `ColumnView`, right-clicking does not select the hovered row anyway.

Testing Done:
Fetched room list for `conference.pidgin.im`, clicked on the rows, and saw that the buttons were enabled (though I think all responses were chats so they were always enabled once one was selected.) Typed some bit of the names and they were filtered.

Reviewed at https://reviews.imfreedom.org/r/2209/
/*
* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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 02111-1301 USA
*
*/
#include "group.h"
#include "debug.h"
#include "purpleprivate.h"
#include "purpleprotocolserver.h"
typedef struct _PurpleGroupPrivate PurpleGroupPrivate;
/******************************************************************************
* Private Data
*****************************************************************************/
struct _PurpleGroupPrivate {
char *name; /* The name of this group. */
gboolean is_constructed; /* Indicates if the group has finished being
constructed. */
};
/* Group property enums */
enum
{
GROUP_PROP_0,
GROUP_PROP_NAME,
GROUP_PROP_LAST
};
/******************************************************************************
* Globals
*****************************************************************************/
static GParamSpec *properties[GROUP_PROP_LAST];
G_DEFINE_TYPE_WITH_PRIVATE(PurpleGroup, purple_group,
PURPLE_TYPE_COUNTING_NODE);
/******************************************************************************
* Group API
*****************************************************************************/
GSList *purple_group_get_accounts(PurpleGroup *group) {
GSList *l = NULL;
PurpleBlistNode *gnode, *cnode, *bnode;
gnode = (PurpleBlistNode *)group;
for (cnode = gnode->child; cnode; cnode = cnode->next) {
if (PURPLE_IS_CHAT(cnode)) {
if (!g_slist_find(l, purple_chat_get_account(PURPLE_CHAT(cnode))))
l = g_slist_append(l, purple_chat_get_account(PURPLE_CHAT(cnode)));
} else if (PURPLE_IS_META_CONTACT(cnode)) {
for (bnode = cnode->child; bnode; bnode = bnode->next) {
if (PURPLE_IS_BUDDY(bnode)) {
if (!g_slist_find(l, purple_buddy_get_account(PURPLE_BUDDY(bnode))))
l = g_slist_append(l, purple_buddy_get_account(PURPLE_BUDDY(bnode)));
}
}
}
}
return l;
}
gboolean purple_group_on_account(PurpleGroup *g, PurpleAccount *account) {
PurpleBlistNode *cnode;
for (cnode = ((PurpleBlistNode *)g)->child; cnode; cnode = cnode->next) {
if (PURPLE_IS_META_CONTACT(cnode)) {
if(purple_meta_contact_on_account((PurpleMetaContact *) cnode, account))
return TRUE;
} else if (PURPLE_IS_CHAT(cnode)) {
PurpleChat *chat = (PurpleChat *)cnode;
if ((!account && purple_account_is_connected(purple_chat_get_account(chat)))
|| purple_chat_get_account(chat) == account)
return TRUE;
}
}
return FALSE;
}
/*
* TODO: If merging, prompt the user if they want to merge.
*/
void purple_group_set_name(PurpleGroup *source, const char *name) {
PurpleGroupPrivate *priv = NULL;
PurpleGroup *dest;
gchar *old_name;
gchar *new_name;
GList *moved_buddies = NULL;
GSList *accts;
g_return_if_fail(PURPLE_IS_GROUP(source));
g_return_if_fail(name != NULL);
priv = purple_group_get_instance_private(source);
new_name = purple_utf8_strip_unprintables(name);
if (*new_name == '\0' || purple_strequal(new_name, priv->name)) {
g_free(new_name);
return;
}
dest = purple_blist_find_group(new_name);
if (dest != NULL && purple_utf8_strcasecmp(priv->name,
purple_group_get_name(dest)) != 0) {
/* We're merging two groups */
PurpleBlistNode *prev, *child, *next;
prev = _purple_blist_get_last_child((PurpleBlistNode*)dest);
child = PURPLE_BLIST_NODE(source)->child;
/*
* TODO: This seems like a dumb way to do this... why not just
* append all children from the old group to the end of the new
* one? Protocols might be expecting to receive an add_buddy() for
* each moved buddy...
*/
while (child)
{
next = child->next;
if (PURPLE_IS_META_CONTACT(child)) {
PurpleBlistNode *bnode;
purple_blist_add_contact((PurpleMetaContact *)child, dest, prev);
for (bnode = child->child; bnode != NULL; bnode = bnode->next) {
purple_blist_add_buddy((PurpleBuddy *)bnode, (PurpleMetaContact *)child,
NULL, bnode->prev);
moved_buddies = g_list_append(moved_buddies, bnode);
}
prev = child;
} else if (PURPLE_IS_CHAT(child)) {
purple_blist_add_chat((PurpleChat *)child, dest, prev);
prev = child;
} else {
purple_debug_error("blistnodetypes", "Unknown child type in group %s", priv->name);
}
child = next;
}
/* Make a copy of the old group name and then delete the old group */
old_name = g_strdup(priv->name);
purple_blist_remove_group(source);
source = dest;
g_free(new_name);
} else {
/* A simple rename */
PurpleBlistNode *cnode, *bnode;
/* Build a GList of all buddies in this group */
for (cnode = PURPLE_BLIST_NODE(source)->child; cnode != NULL; cnode = cnode->next) {
if (PURPLE_IS_META_CONTACT(cnode))
for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
moved_buddies = g_list_append(moved_buddies, bnode);
}
purple_blist_update_groups_cache(source, new_name);
old_name = priv->name;
priv->name = new_name;
g_object_notify_by_pspec(G_OBJECT(source), properties[GROUP_PROP_NAME]);
}
/* Save our changes */
purple_blist_save_node(purple_blist_get_default(),
PURPLE_BLIST_NODE(source));
/* Update the UI */
purple_blist_update_node(purple_blist_get_default(),
PURPLE_BLIST_NODE(source));
/* Notify all protocols */
/* TODO: Is this condition needed? Seems like it would always be TRUE */
if(old_name && !purple_strequal(priv->name, old_name)) {
for (accts = purple_group_get_accounts(source); accts;
accts = g_slist_delete_link(accts, accts)) {
PurpleAccount *account = accts->data;
PurpleConnection *gc = NULL;
PurpleProtocol *protocol = NULL;
GList *l = NULL, *buddies = NULL;
gc = purple_account_get_connection(account);
if(gc)
protocol = purple_connection_get_protocol(gc);
if(!protocol)
continue;
for(l = moved_buddies; l; l = l->next) {
PurpleBuddy *buddy = PURPLE_BUDDY(l->data);
if(buddy && purple_buddy_get_account(buddy) == account)
buddies = g_list_append(buddies, (PurpleBlistNode *)buddy);
}
if(PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, rename_group)) {
purple_protocol_server_rename_group(PURPLE_PROTOCOL_SERVER(protocol),
gc, old_name, source,
buddies);
} else {
GList *cur, *groups = NULL;
/* Make a list of what the groups each buddy is in */
for(cur = buddies; cur; cur = cur->next) {
PurpleBlistNode *node = (PurpleBlistNode *)cur->data;
groups = g_list_prepend(groups, node->parent->parent);
}
purple_account_remove_buddies(account, buddies, groups);
g_list_free(groups);
purple_account_add_buddies(account, buddies, NULL);
}
g_list_free(buddies);
}
}
g_list_free(moved_buddies);
g_free(old_name);
g_object_notify_by_pspec(G_OBJECT(source), properties[GROUP_PROP_NAME]);
}
const char *purple_group_get_name(PurpleGroup *group) {
PurpleGroupPrivate *priv = NULL;
g_return_val_if_fail(PURPLE_IS_GROUP(group), NULL);
priv = purple_group_get_instance_private(group);
return priv->name;
}
/******************************************************************************
* GObject Stuff
*****************************************************************************/
/* Set method for GObject properties */
static void
purple_group_set_property(GObject *obj, guint param_id, const GValue *value,
GParamSpec *pspec)
{
PurpleGroup *group = PURPLE_GROUP(obj);
PurpleGroupPrivate *priv = purple_group_get_instance_private(group);
switch (param_id) {
case GROUP_PROP_NAME:
if (priv->is_constructed)
purple_group_set_name(group, g_value_get_string(value));
else
priv->name =
purple_utf8_strip_unprintables(g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* Get method for GObject properties */
static void
purple_group_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *pspec)
{
PurpleGroup *group = PURPLE_GROUP(obj);
switch (param_id) {
case GROUP_PROP_NAME:
g_value_set_string(value, purple_group_get_name(group));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* GObject initialization function */
static void
purple_group_init(G_GNUC_UNUSED PurpleGroup *group) {
}
/* Called when done constructing */
static void
purple_group_constructed(GObject *object) {
PurpleGroup *group = PURPLE_GROUP(object);
PurpleGroupPrivate *priv = purple_group_get_instance_private(group);
G_OBJECT_CLASS(purple_group_parent_class)->constructed(object);
purple_blist_new_node(purple_blist_get_default(),
PURPLE_BLIST_NODE(group));
priv->is_constructed = TRUE;
}
/* GObject finalize function */
static void
purple_group_finalize(GObject *object) {
PurpleGroupPrivate *priv = purple_group_get_instance_private(
PURPLE_GROUP(object));
g_free(priv->name);
G_OBJECT_CLASS(purple_group_parent_class)->finalize(object);
}
/* Class initializer function */
static void
purple_group_class_init(PurpleGroupClass *klass) {
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
obj_class->finalize = purple_group_finalize;
obj_class->constructed = purple_group_constructed;
/* Setup properties */
obj_class->get_property = purple_group_get_property;
obj_class->set_property = purple_group_set_property;
properties[GROUP_PROP_NAME] = g_param_spec_string(
"name",
"Name",
"Name of the group.",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS
);
g_object_class_install_properties(obj_class, GROUP_PROP_LAST, properties);
}
PurpleGroup *
purple_group_new(const char *name) {
PurpleGroup *group;
if (name == NULL || name[0] == '\0')
name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
if (g_strcmp0(name, "Buddies") == 0)
name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
if (g_strcmp0(name, _purple_blist_get_localized_default_group_name()) == 0)
name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
group = purple_blist_find_group(name);
if (group != NULL)
return group;
return g_object_new(PURPLE_TYPE_GROUP, "name", name, NULL);
}