/* * Telapathy Inspector - A Telepathy client which exposes Telepathy interfaces. * Meant to inspect and/or test connection managers. * * ti-page-channel-group.c: * A GtkNotebook page exposing org.freedesktop.Telepathy.Channel.Interface.Group * functionality. * * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia * Author - Daniel d'Andrada T. de Carvalho <daniel.carvalho@indt.org.br> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "ti-page-channel-group.h" #include "ti-page-priv.h" #include "ti-channel.h" #include "ti-constants.h" #include "ti-dlg-get-text.h" #include "ti-dlg-add-members.h" #include "ti-config.h" #include "ti-preferences.h" #include "ti-util.h" #include <glade/glade.h> #include <string.h> enum { TI_COLUMN_MEMBERS_LIST_HANDLE = 0, TI_COLUMN_MEMBERS_LIST_NAME, TI_COLUMN_MEMBERS_LIST_STATUS, TI_COLUMN_MEMBERS_LIST_N_COLUMNS }; #define TI_GROUP_MEMBER_STATUS_REGULAR "member" #define TI_GROUP_MEMBER_STATUS_LOCAL_PENDING "local pending" #define TI_GROUP_MEMBER_STATUS_REMOTE_PENDING "remote pending" struct _TIPageChannelGroupClass { TIPageClass parent; }; G_DEFINE_TYPE (TIPageChannelGroup, ti_page_channel_group, TI_TYPE_PAGE); /* Function prototypes */ static void _ti_page_channel_group_setup_page (TIPage* page, GladeXML* glade_xml); static void _ti_page_channel_group_build_members_treeview (TIPageChannelGroup* page_channel_group, GladeXML* glade_xml); static void _ti_page_channel_group_fill_members_list (TIPageChannelGroup* page_channel_group); static void _ti_page_channel_group_append_members_to_list (TIPageChannelGroup* page_channel_group, GArray* handles, const gchar* status); static void _ti_page_channel_group_setup_group_flags (TIPageChannelGroup* page_channel_group, GladeXML* glade_xml); static void _ti_page_channel_group_remove_selected_members (TIPageChannelGroup* page_channel_group); static void _ti_page_channel_group_add_members (TIPageChannelGroup* page_channel_group); static void _ti_page_channel_group_members_changed (TIPageChannelGroup* page_channel_group, const gchar* message, GArray* added, GArray* removed, GArray* local_pending, GArray* remote_pending, guint actor, guint reason); static void _ti_page_channel_group_log_members_changed (TIPageChannelGroup* page_channel_group, const gchar* message, GArray* added, GArray* removed, GArray* local_pending, GArray* remote_pending, guint actor, guint reason); static void _ti_page_channel_group_remove_members (TIPageChannelGroup* page_channel_group, GArray* removed_handles); static void _ti_page_channel_group_remove_member (TIPageChannelGroup* page_channel_group, guint handle); static void _ti_page_channel_group_update_button_remove_sensitivity (TIPageChannelGroup* page_channel_group); static void _ti_page_channel_group_clear_log (TIPageChannelGroup* page_channel_group); static void _ti_page_channel_group_group_flags_changed (TIPageChannelGroup* page_channel_group, guint added, guint removed); static void _ti_page_channel_group_log_group_flags_changed (TIPageChannelGroup* page_channel_group, guint added, guint removed); static void _ti_page_channel_group_refresh_group_flags_checkboxes (TIPageChannelGroup* page_channel_group); static void _ti_page_channel_group_update_selection_permissions (TIPageChannelGroup* page_channel_group); static void _group_flags_to_string (GString* text, guint flags); static void _ti_page_channel_group_handle_display_mode_changed (TIPageChannelGroup* page_channel_group, guint handle_display_mode); static gboolean _ti_page_channel_get_contact_row (TIPageChannelGroup* page_channel_group, guint contact_handle, GtkTreeIter* iter); /** * Instance private data. */ 00090 struct _TIPageChannelGroupPrivate { TIChannel* channel; TIPreferences* preferences; TIHandleMapper* handle_mapper; guint group_flags; TIDlgAddMembers* dialog_add_members; TIDlgGetText* dialog_get_text; GtkListStore* members_list; GtkTreeView* members_tree_view; GtkTreeSelection* members_selection; GtkWidget* checkbutton_can_add; GtkWidget* checkbutton_can_remove; GtkWidget* checkbutton_can_rescind; GtkWidget* checkbutton_message_add; GtkWidget* checkbutton_message_remove; GtkWidget* checkbutton_message_accept; GtkWidget* checkbutton_message_reject; GtkWidget* checkbutton_message_rescind; GtkWidget* checkbutton_channel_specific_handles; GtkButton* button_remove_members; GtkButton* button_add_members; GtkTextBuffer* textbuffer_event_log; }; typedef struct _TIPageChannelGroupPrivate TIPageChannelGroupPrivate; #define TI_PAGE_CHANNEL_GROUP_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), TI_TYPE_PAGE_CHANNEL_GROUP, TIPageChannelGroupPrivate)) /** * Drop all references to other objects. */ static void ti_page_channel_group_dispose (GObject *object) { TIPageChannelGroup *page_channel_group = TI_PAGE_CHANNEL_GROUP (object); TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); if (priv->channel != NULL) { g_signal_handlers_disconnect_by_func(priv->channel, G_CALLBACK (_ti_page_channel_group_members_changed), page_channel_group); g_signal_handlers_disconnect_by_func(priv->channel, G_CALLBACK (_ti_page_channel_group_group_flags_changed), page_channel_group); g_object_unref (priv->channel); priv->channel = NULL; } if (priv->preferences != NULL) { g_signal_handlers_disconnect_by_func(priv->preferences, G_CALLBACK (_ti_page_channel_group_handle_display_mode_changed), page_channel_group); g_object_unref (priv->preferences); priv->preferences = NULL; } TI_OBJ_UNREF (priv->handle_mapper); TI_OBJ_UNREF (priv->dialog_add_members); TI_OBJ_UNREF (priv->dialog_get_text); TI_OBJ_UNREF (priv->members_list); G_OBJECT_CLASS (ti_page_channel_group_parent_class)->dispose (object); } /** * Class initialization. */ static void ti_page_channel_group_class_init (TIPageChannelGroupClass *ti_page_channel_group_class) { GObjectClass *gobject_class = G_OBJECT_CLASS (ti_page_channel_group_class); TIPageClass* page_class = TI_PAGE_CLASS (ti_page_channel_group_class); /* override base object methods */ gobject_class->dispose = ti_page_channel_group_dispose; page_class->setup_page = _ti_page_channel_group_setup_page; /* Add private */ g_type_class_add_private (ti_page_channel_group_class, sizeof (TIPageChannelGroupPrivate)); } /** * Instance initialization. */ static void ti_page_channel_group_init (TIPageChannelGroup *ti_page_channel_group) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (ti_page_channel_group); priv->channel = NULL; priv->preferences = ti_preferences_new (); priv->handle_mapper = NULL; priv->dialog_add_members = NULL; priv->dialog_get_text = NULL; priv->members_list = NULL; } /** * Returns a new instance. */ TIPageChannelGroup* ti_page_channel_group_new (GtkNotebook* parent_notebook, GtkWindow* parent_window, TIChannel* channel, TIHandleMapper* handle_mapper) { TIPageChannelGroup* page_channel_group = NULL; TIPageChannelGroupPrivate *priv = NULL; g_assert (channel != NULL); page_channel_group = g_object_new (TI_TYPE_PAGE_CHANNEL_GROUP, NULL); priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); priv->channel = channel; g_object_ref (channel); priv->handle_mapper = handle_mapper; g_object_ref (handle_mapper); g_signal_connect_swapped (channel, "members-changed", G_CALLBACK (_ti_page_channel_group_members_changed), page_channel_group); g_signal_connect_swapped (channel, "group-flags-changed", G_CALLBACK (_ti_page_channel_group_group_flags_changed), page_channel_group); g_signal_connect_swapped (priv->preferences, "handle-display-mode-changed", G_CALLBACK (_ti_page_channel_group_handle_display_mode_changed), page_channel_group); priv->dialog_add_members = ti_dlg_add_members_new (parent_window, handle_mapper); if (priv->dialog_add_members == NULL) { g_object_unref (page_channel_group); page_channel_group = NULL; goto CLEAN_UP; } priv->dialog_get_text = ti_dlg_get_text_new (parent_window, "Enter message:"); if (priv->dialog_get_text == NULL) { g_object_unref (page_channel_group); page_channel_group = NULL; goto CLEAN_UP; } _ti_page_new ((TIPage**)&page_channel_group, parent_notebook, "page-channel-group.xml"); CLEAN_UP: return page_channel_group; } /** * Setup Page - Helper Function */ static void _ti_page_channel_group_setup_page (TIPage* page, GladeXML* glade_xml) { TIPageChannelGroup* page_channel_group = TI_PAGE_CHANNEL_GROUP (page); TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); gboolean can_add; GtkWidget* widget; // Group Flags _ti_page_channel_group_setup_group_flags (page_channel_group, glade_xml); // Members List _ti_page_channel_group_build_members_treeview (page_channel_group, glade_xml); _ti_page_channel_group_fill_members_list (page_channel_group); // Button Remove Members priv->button_remove_members = GTK_BUTTON (glade_xml_get_widget(glade_xml, "button_remove_members")); g_assert (GTK_IS_BUTTON (priv->button_remove_members)); g_signal_connect_swapped (priv->button_remove_members, "clicked", G_CALLBACK (_ti_page_channel_group_remove_selected_members), page_channel_group); // Button Add Members priv->button_add_members = GTK_BUTTON (glade_xml_get_widget(glade_xml, "button_add_members")); g_assert (GTK_IS_BUTTON (priv->button_add_members)); g_signal_connect_swapped (priv->button_add_members, "clicked", G_CALLBACK (_ti_page_channel_group_add_members), page_channel_group); can_add = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_CAN_ADD) != 0; gtk_widget_set_sensitive (GTK_WIDGET (priv->button_remove_members), can_add); // Button Refresh Members widget = glade_xml_get_widget(glade_xml, "button_refresh_members"); g_assert (GTK_IS_BUTTON (widget)); g_signal_connect_swapped (GTK_BUTTON (widget), "clicked", G_CALLBACK (_ti_page_channel_group_fill_members_list), page_channel_group); // TextView Event Log widget = glade_xml_get_widget(glade_xml, "textview_event_log"); g_assert (GTK_IS_TEXT_VIEW (widget)); priv->textbuffer_event_log = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)); // Button Clear Event Log widget = glade_xml_get_widget(glade_xml, "button_event_log_clear"); g_assert (GTK_IS_BUTTON (widget)); g_signal_connect_swapped (GTK_BUTTON (widget), "clicked", G_CALLBACK (_ti_page_channel_group_clear_log), page_channel_group); } /** * Build Members Treeview */ static void _ti_page_channel_group_build_members_treeview (TIPageChannelGroup* page_channel_group, GladeXML* glade_xml) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GtkCellRenderer *renderer; GtkTreeViewColumn *column; priv->members_tree_view = GTK_TREE_VIEW (glade_xml_get_widget(glade_xml, "treeview_members")); g_assert (priv->members_tree_view != NULL && GTK_IS_TREE_VIEW (priv->members_tree_view)); priv->members_list = gtk_list_store_new (3, G_TYPE_UINT /*handle*/, G_TYPE_STRING /*name*/, G_TYPE_STRING /*status*/); gtk_tree_view_set_model (priv->members_tree_view, GTK_TREE_MODEL (priv->members_list)); renderer = gtk_cell_renderer_text_new (); if (ti_preferences_get_handle_display_mode (priv->preferences) == TI_PREFERENCES_HANDLE_DISPLAY_HANDLE) { column = gtk_tree_view_column_new_with_attributes ("Handle", renderer, "text", 0, NULL); gtk_tree_view_append_column (priv->members_tree_view, column); } else { column = gtk_tree_view_column_new_with_attributes ("Name", renderer, "text", 1, NULL); gtk_tree_view_append_column (priv->members_tree_view, column); } // Status column. Displays something like "local pending", "remote pending" and "regular member". column = gtk_tree_view_column_new_with_attributes ("Status", renderer, "text", 2, NULL); gtk_tree_view_append_column (priv->members_tree_view, column); priv->members_selection = gtk_tree_view_get_selection (priv->members_tree_view); g_signal_connect_swapped (priv->members_selection, "changed", G_CALLBACK (_ti_page_channel_group_update_button_remove_sensitivity), page_channel_group); gtk_tree_selection_set_mode (priv->members_selection, GTK_SELECTION_MULTIPLE); } /** * Fill Members List */ static void _ti_page_channel_group_fill_members_list (TIPageChannelGroup* page_channel_group) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GArray* handles = NULL; GError* error = NULL; gtk_list_store_clear (priv->members_list); // Get Regular Members handles = ti_channel_igroup_get_members (priv->channel, &error); if (error != NULL) { goto CLEAN_UP; } _ti_page_channel_group_append_members_to_list (page_channel_group, handles, TI_GROUP_MEMBER_STATUS_REGULAR); g_array_free (handles, TRUE); handles = NULL; // Get Local Pending Members handles = ti_channel_igroup_get_local_pending_members (priv->channel, &error); if (error != NULL) { goto CLEAN_UP; } _ti_page_channel_group_append_members_to_list (page_channel_group, handles, TI_GROUP_MEMBER_STATUS_LOCAL_PENDING); g_array_free (handles, TRUE); handles = NULL; // Get Remote Pending Members handles = ti_channel_igroup_get_remote_pending_members (priv->channel, &error); if (error != NULL) { goto CLEAN_UP; } _ti_page_channel_group_append_members_to_list (page_channel_group, handles, TI_GROUP_MEMBER_STATUS_REMOTE_PENDING); g_array_free (handles, TRUE); handles = NULL; CLEAN_UP: if (handles != NULL) { g_array_free (handles, TRUE); } } /** * Append Members To List */ static void _ti_page_channel_group_append_members_to_list (TIPageChannelGroup* page_channel_group, GArray* handles, const gchar* status) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GtkTreeIter iter; guint i; guint handle; gchar* name; /* Fill the list. */ for (i = 0; i < handles->len; i++) { handle = g_array_index (handles, guint, i); name = ti_handle_mapper_get_contact_handle_name (priv->handle_mapper, handle); if (name == NULL) { name = g_strdup_printf ("%u", handle); } // If there's not already a row for that contact, we create one. if (!_ti_page_channel_get_contact_row (page_channel_group, handle, &iter)) { gtk_list_store_append (priv->members_list, &iter); } gtk_list_store_set (priv->members_list, &iter, TI_COLUMN_MEMBERS_LIST_HANDLE, handle, TI_COLUMN_MEMBERS_LIST_NAME, name, TI_COLUMN_MEMBERS_LIST_STATUS, status, -1); g_free (name); } } /** * Setup Group Flags */ static void _ti_page_channel_group_setup_group_flags (TIPageChannelGroup* page_channel_group, GladeXML* glade_xml) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GError* error; /*** Get widgets from glade object. ***/ priv->checkbutton_can_add = glade_xml_get_widget(glade_xml, "checkbutton_can_add"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_can_add)); priv->checkbutton_can_remove = glade_xml_get_widget(glade_xml, "checkbutton_can_remove"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_can_remove)); priv->checkbutton_can_rescind = glade_xml_get_widget(glade_xml, "checkbutton_can_rescind"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_can_rescind)); priv->checkbutton_message_add = glade_xml_get_widget(glade_xml, "checkbutton_message_add"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_message_add)); priv->checkbutton_message_remove = glade_xml_get_widget(glade_xml, "checkbutton_message_remove"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_message_remove)); priv->checkbutton_message_accept = glade_xml_get_widget(glade_xml, "checkbutton_message_accept"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_message_accept)); priv->checkbutton_message_reject = glade_xml_get_widget(glade_xml, "checkbutton_message_reject"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_message_reject)); priv->checkbutton_message_rescind = glade_xml_get_widget(glade_xml, "checkbutton_message_rescind"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_message_rescind)); priv->checkbutton_channel_specific_handles = glade_xml_get_widget(glade_xml, "checkbutton_channel_specific_handles"); g_assert (GTK_IS_CHECK_BUTTON (priv->checkbutton_channel_specific_handles)); /*** Set checkbutton states ***/ priv->group_flags = ti_channel_igroup_get_group_flags (priv->channel, &error); if (error != NULL) { // TODO: Display a message or something. g_error_free (error); return; } _ti_page_channel_group_refresh_group_flags_checkboxes (page_channel_group); } /** * Remove Selected Members */ static void _ti_page_channel_group_remove_selected_members (TIPageChannelGroup* page_channel_group) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GError* error = NULL; GArray* members = NULL; gchar* message = NULL; gboolean ok; members = ti_get_selected_elements (priv->members_selection, TI_COLUMN_MEMBERS_LIST_HANDLE, G_TYPE_UINT); g_assert (members != NULL); if ((priv->group_flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE) != 0) { ok = ti_dlg_get_text_run (priv->dialog_get_text, &message); if (!ok) goto CLEAN_UP; } ti_channel_igroup_remove_members (priv->channel, members, message, &error); if (error != NULL) { // TODO: Display a message or something. g_error_free (error); } CLEAN_UP: g_free (message); g_array_free (members, TRUE); } /** * Add Members */ static void _ti_page_channel_group_add_members (TIPageChannelGroup* page_channel_group) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); gboolean ok; GArray* handles = NULL; GError* error = NULL; gchar* message = NULL; GArray* selected_handles = NULL; selected_handles = ti_get_selected_elements (priv->members_selection, TI_COLUMN_MEMBERS_LIST_HANDLE, G_TYPE_UINT); ok = ti_dlg_add_members_run (priv->dialog_add_members, selected_handles, &handles, &message); if (!ok) { goto CLEAN_UP; } ti_channel_igroup_add_members (priv->channel, handles, message, &error); if (error != NULL) { // TODO: Display a message or something; } CLEAN_UP: g_free (message); g_array_free (selected_handles, TRUE); if (handles != NULL) g_array_free (handles, TRUE); if (error != NULL) g_error_free (error); } /** * Members Changed */ static void _ti_page_channel_group_members_changed (TIPageChannelGroup* page_channel_group, const gchar* message, GArray* added, GArray* removed, GArray* local_pending, GArray* remote_pending, guint actor, guint reason) { g_assert (added != NULL); g_assert (local_pending != NULL); g_assert (remote_pending != NULL); _ti_page_channel_group_log_members_changed (page_channel_group, message, added, removed, local_pending, remote_pending, actor, reason); _ti_page_channel_group_append_members_to_list (page_channel_group, added, TI_GROUP_MEMBER_STATUS_REGULAR); _ti_page_channel_group_append_members_to_list (page_channel_group, local_pending, TI_GROUP_MEMBER_STATUS_LOCAL_PENDING); _ti_page_channel_group_append_members_to_list (page_channel_group, remote_pending, TI_GROUP_MEMBER_STATUS_REMOTE_PENDING); _ti_page_channel_group_remove_members (page_channel_group, removed); } /** * Remove Members */ static void _ti_page_channel_group_remove_members (TIPageChannelGroup* page_channel_group, GArray* removed_handles) { guint i; guint handle; for (i = 0; i < removed_handles->len; i++) { handle = g_array_index (removed_handles, guint, i); _ti_page_channel_group_remove_member (page_channel_group, handle); } } /** * Remove Member */ static void _ti_page_channel_group_remove_member (TIPageChannelGroup* page_channel_group, guint handle) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); gboolean ok; GtkTreeIter iter; gboolean removed = FALSE; guint member_handle; ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->members_list), &iter); if (!ok) { return; // The list is empty. } while (ok && !removed) { gtk_tree_model_get (GTK_TREE_MODEL (priv->members_list), &iter, TI_COLUMN_MEMBERS_LIST_HANDLE, &member_handle, -1); if (member_handle == handle) { gtk_list_store_remove (priv->members_list, &iter); removed = TRUE; } else { ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->members_list), &iter); } } } /** * Update Button Remove Sensitivity */ static void _ti_page_channel_group_update_button_remove_sensitivity (TIPageChannelGroup* page_channel_group) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); gint selection_count; selection_count = gtk_tree_selection_count_selected_rows (priv->members_selection); gtk_widget_set_sensitive (GTK_WIDGET (priv->button_remove_members), selection_count > 0); } /** * Log Members Changed */ static void _ti_page_channel_group_log_members_changed (TIPageChannelGroup* page_channel_group, const gchar* message, GArray* added, GArray* removed, GArray* local_pending, GArray* remote_pending, guint actor, guint reason) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GtkTextIter iter; GString* text = NULL; guint i; guint handle; text = g_string_new ("=== MembersChanged ===\n"); // Added g_string_append (text, " Added:"); for (i = 0; i < added->len; i++) { handle = g_array_index (added, guint, i); g_string_append_printf (text, " %u", handle); } g_string_append (text, "\n"); // Removed g_string_append (text, " Removed:"); for (i = 0; i < removed->len; i++) { handle = g_array_index (removed, guint, i); g_string_append_printf (text, " %u", handle); } g_string_append (text, "\n"); // Local pending g_string_append (text, " Local pending:"); for (i = 0; i < local_pending->len; i++) { handle = g_array_index (local_pending, guint, i); g_string_append_printf (text, " %u", handle); } g_string_append (text, "\n"); // Remote pending g_string_append (text, " Remote pending:"); for (i = 0; i < remote_pending->len; i++) { handle = g_array_index (remote_pending, guint, i); g_string_append_printf (text, " %u", handle); } g_string_append (text, "\n"); // Actor g_string_append_printf (text, " Actor: %u\n", actor); // Reason g_string_append_printf (text, " Reason: %u", reason); switch (reason) { case TI_CHANNEL_GROUP_CHANGE_REASON_NONE: g_string_append (text, " (None)\n"); break; case TI_CHANNEL_GROUP_CHANGE_REASON_OFFLINE: g_string_append (text, " (Offline)\n"); break; case TI_CHANNEL_GROUP_CHANGE_REASON_KICKED: g_string_append (text, " (Kicked)\n"); break; case TI_CHANNEL_GROUP_CHANGE_REASON_BUSY: g_string_append (text, "(Busy)\n"); break; case TI_CHANNEL_GROUP_CHANGE_REASON_INVITED: g_string_append (text, " (Invited)\n"); break; default: g_string_append (text, " (Unknown/Invalid)\n"); } // Space for next entry g_string_append (text, "\n"); // Append to event log gtk_text_buffer_get_end_iter (priv->textbuffer_event_log, &iter); gtk_text_buffer_insert (priv->textbuffer_event_log, &iter, text->str, -1); // Clean up if (text != NULL) g_string_free (text, TRUE); } /** * Clear Log */ static void _ti_page_channel_group_clear_log (TIPageChannelGroup* page_channel_group) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GtkTextIter start_iter; GtkTextIter end_iter; gtk_text_buffer_get_start_iter (priv->textbuffer_event_log, &start_iter); gtk_text_buffer_get_end_iter (priv->textbuffer_event_log, &end_iter); gtk_text_buffer_delete (priv->textbuffer_event_log, &start_iter, &end_iter); } /** * Group Flags Changed */ static void _ti_page_channel_group_group_flags_changed (TIPageChannelGroup* page_channel_group, guint added, guint removed) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); gboolean can_add; // Log it. _ti_page_channel_group_log_group_flags_changed (page_channel_group, added, removed); priv->group_flags = priv->group_flags + added - removed; _ti_page_channel_group_refresh_group_flags_checkboxes (page_channel_group); can_add = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_CAN_ADD) != 0; gtk_widget_set_sensitive (GTK_WIDGET (priv->button_remove_members), can_add); _ti_page_channel_group_update_selection_permissions (page_channel_group); _ti_page_channel_group_update_button_remove_sensitivity (page_channel_group); } /** * Refresh Group Flags Checkboxes */ static void _ti_page_channel_group_refresh_group_flags_checkboxes (TIPageChannelGroup* page_channel_group) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); gboolean active; active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_CAN_ADD) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_can_add), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_CAN_REMOVE) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_can_remove), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_CAN_RESCIND) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_can_rescind), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_ADD) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_message_add), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_message_remove), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_message_accept), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_REJECT) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_message_reject), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_message_rescind), active); active = (priv->group_flags & TI_CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES) != 0; gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbutton_channel_specific_handles), active); } /** * Update Selection Permissions */ static void _ti_page_channel_group_update_selection_permissions (TIPageChannelGroup* page_channel_group) { /* TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); if ((priv->group_flags & TI_CHANNEL_GROUP_FLAG_CAN_REMOVE) != 0) { gtk_tree_selection_set_mode (priv->members_selection, GTK_SELECTION_MULTIPLE); } else { gtk_tree_selection_set_mode (priv->members_selection, GTK_SELECTION_NONE); } if ((priv->group_flags & TI_CHANNEL_GROUP_FLAG_CAN_RESCIND) != 0) { gtk_tree_selection_set_mode (priv->remote_pending_selection, GTK_SELECTION_MULTIPLE); } else { gtk_tree_selection_set_mode (priv->remote_pending_selection, GTK_SELECTION_NONE); }*/ } /** * Log Group Flags Changed */ static void _ti_page_channel_group_log_group_flags_changed (TIPageChannelGroup* page_channel_group, guint added, guint removed) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GtkTextIter iter; GString* text; text = g_string_new ("=== GroupFlagsChanged ===\n"); g_string_append (text, " Added:"); _group_flags_to_string (text, added); g_string_append (text, "\n"); g_string_append (text, " Removed:"); _group_flags_to_string (text, removed); g_string_append (text, "\n"); // Space for the next entry. g_string_append (text, "\n"); // Append to event log gtk_text_buffer_get_end_iter (priv->textbuffer_event_log, &iter); gtk_text_buffer_insert (priv->textbuffer_event_log, &iter, text->str, -1); if (text != NULL) g_string_free (text, TRUE); } /** * Group Flags To String */ static void _group_flags_to_string (GString* text, guint flags) { if ((flags & TI_CHANNEL_GROUP_FLAG_CAN_ADD) != 0) g_string_append_printf (text, " Can Add (%u)", TI_CHANNEL_GROUP_FLAG_CAN_ADD); if ((flags & TI_CHANNEL_GROUP_FLAG_CAN_REMOVE) != 0) g_string_append_printf (text, " Can Remove (%u)", TI_CHANNEL_GROUP_FLAG_CAN_REMOVE); if ((flags & TI_CHANNEL_GROUP_FLAG_CAN_RESCIND) != 0) g_string_append_printf (text, " Can Rescind (%u)", TI_CHANNEL_GROUP_FLAG_CAN_RESCIND); if ((flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_ADD) != 0) g_string_append_printf (text, " Message Add (%u)", TI_CHANNEL_GROUP_FLAG_MESSAGE_ADD); if ((flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE) != 0) g_string_append_printf (text, " Message Remove (%u)", TI_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE); if ((flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT) != 0) g_string_append_printf (text, " Message Accept (%u)", TI_CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT); if ((flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_REJECT) != 0) g_string_append_printf (text, " Message Reject (%u)", TI_CHANNEL_GROUP_FLAG_MESSAGE_REJECT); if ((flags & TI_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND) != 0) g_string_append_printf (text, " Message Rescind (%u)", TI_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND); if ((flags & TI_CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES) != 0) g_string_append_printf (text, " Channel Specific Handles (%u)", TI_CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES); } /** * Handle Display Mode Changed */ static void _ti_page_channel_group_handle_display_mode_changed (TIPageChannelGroup* page_channel_group, guint handle_display_mode) { TIPageChannelGroupPrivate *priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); GtkTreeViewColumn* contact_handle_column; GtkCellRenderer* renderer; GList* renderers_list = NULL; g_assert (TI_IS_PAGE_CHANNEL_GROUP (page_channel_group)); contact_handle_column = gtk_tree_view_get_column (priv->members_tree_view, 0); // It's the first column. renderers_list = gtk_tree_view_column_get_cell_renderers (contact_handle_column); g_assert (g_list_length (renderers_list) == 1); renderer = GTK_CELL_RENDERER (renderers_list->data); if (handle_display_mode == TI_PREFERENCES_HANDLE_DISPLAY_HANDLE) { gtk_tree_view_column_set_title (contact_handle_column, "Handle"); gtk_tree_view_column_set_attributes (contact_handle_column, renderer, "text", TI_COLUMN_MEMBERS_LIST_HANDLE, NULL); } else // TI_PREFERENCES_HANDLE_DISPLAY_NAME { gtk_tree_view_column_set_title (contact_handle_column, "Name"); gtk_tree_view_column_set_attributes (contact_handle_column, renderer, "text", TI_COLUMN_MEMBERS_LIST_NAME, NULL); } // Clean up g_list_free (renderers_list); } /** * Get Contact Row */ static gboolean _ti_page_channel_get_contact_row (TIPageChannelGroup* page_channel_group, guint contact_handle, GtkTreeIter* iter) { TIPageChannelGroupPrivate* priv = TI_PAGE_CHANNEL_GROUP_GET_PRIVATE (page_channel_group); gboolean ok; gboolean found = FALSE; guint curr_handle; ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->members_list), iter); while (ok && !found) { gtk_tree_model_get (GTK_TREE_MODEL (priv->members_list), iter, TI_COLUMN_MEMBERS_LIST_HANDLE, &curr_handle, -1); if (curr_handle == contact_handle) { found = TRUE; } else { ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->members_list), iter); } } return found; }