From 544eceba439fbb1f6cf6952f3f4472e7e9817695 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Mon, 17 Dec 2012 00:26:26 +0100 Subject: [PATCH 1/1] Split GTK roster delegate into separate class --- Makefile | 3 +- src/core/main.m | 6 +- src/gui/gtk/JubGtkRosterUI.h | 15 ++ src/gui/gtk/JubGtkRosterUI.m | 295 +++++++++++++++++++++++++++++++++++ src/gui/gtk/JubGtkUI.h | 11 +- src/gui/gtk/JubGtkUI.m | 295 ++--------------------------------- 6 files changed, 337 insertions(+), 288 deletions(-) create mode 100644 src/gui/gtk/JubGtkRosterUI.h create mode 100644 src/gui/gtk/JubGtkRosterUI.m diff --git a/Makefile b/Makefile index 22d6ae5..71e4451 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ PROG = jubjub$(PROG_SUFFIX) SRCS = src/core/main.m \ - src/gui/gtk/JubGtkUI.m + src/gui/gtk/JubGtkUI.m \ + src/gui/gtk/JubGtkRosterUI.m include buildsys.mk diff --git a/src/core/main.m b/src/core/main.m index ff97a3b..6b03d95 100644 --- a/src/core/main.m +++ b/src/core/main.m @@ -18,6 +18,8 @@ OF_APPLICATION_DELEGATE(AppDelegate) - (void)applicationDidFinishLaunching { ui = [[JubGtkUI alloc] init]; + id rosterDelegate = + [ui rosterDelegate]; connection = [[XMPPConnection alloc] init]; [connection addDelegate: self]; @@ -29,10 +31,10 @@ OF_APPLICATION_DELEGATE(AppDelegate) [connection connect]; [connection handleConnection]; - [connection addDelegate: [ui rosterDelegate]]; + [connection addDelegate: rosterDelegate]; roster = [[XMPPRoster alloc] initWithConnection: connection]; - [roster addDelegate: [ui rosterDelegate]]; + [roster addDelegate: rosterDelegate]; [roster addDelegate: self]; [ui startUIThread]; diff --git a/src/gui/gtk/JubGtkRosterUI.h b/src/gui/gtk/JubGtkRosterUI.h new file mode 100644 index 0000000..3244ad5 --- /dev/null +++ b/src/gui/gtk/JubGtkRosterUI.h @@ -0,0 +1,15 @@ +#import +#import +#include + +@interface JubGtkRosterUI: OFObject +{ + GtkTreeStore *roster_model; + GtkTreeModelFilter *roster_filter; + OFMapTable *groupMap; + OFMutableDictionary *contactMap; + OFCountedSet *presences; + GtkBuilder *builder; +} +- initWithBuilder: (GtkBuilder*)builder; +@end diff --git a/src/gui/gtk/JubGtkRosterUI.m b/src/gui/gtk/JubGtkRosterUI.m new file mode 100644 index 0000000..acdffb6 --- /dev/null +++ b/src/gui/gtk/JubGtkRosterUI.m @@ -0,0 +1,295 @@ +#import "JubGtkRosterUI.h" +#import "JubGObjectMap.h" + +static gboolean filter_roster_by_presence(GtkTreeModel *model, + GtkTreeIter *iter, gpointer data) +{ + char *jid_s; + OFString *jid; + OFCountedSet *presences = data; + + gtk_tree_model_get(model, iter, 1, &jid_s, -1); + + // Groups have no JID + if (!jid_s) + return TRUE; + + jid = [[OFString alloc] initWithUTF8String: jid_s]; + + g_free(jid_s); + + int num = [presences countForObject: jid]; + if (num) { + [jid release]; + return TRUE; + } else { + [jid release]; + return FALSE; + } +} + +@implementation JubGtkRosterUI +- initWithBuilder: (GtkBuilder*)builder_ +{ + self = [super init]; + + @try { + groupMap = [[OFMapTable alloc] + initWithKeyFunctions: keyFunctions + valueFunctions: rowRefFunctions]; + contactMap = [[OFMutableDictionary alloc] init]; + presences = [[OFCountedSet alloc] init]; + + builder = g_object_ref(builder_); + + roster_model = GTK_TREE_STORE(gtk_builder_get_object(builder, + "RosterTreeStore")); + + roster_filter = GTK_TREE_MODEL_FILTER( + gtk_builder_get_object(builder, "RosterTreeModelFilter")); + + gtk_tree_model_filter_set_visible_func(roster_filter, + filter_roster_by_presence, presences, NULL); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [groupMap release]; + [contactMap release]; + [presences release]; + + if (roster_model) + g_object_unref(roster_model); + + if (roster_filter) + g_object_unref(roster_filter); + + g_object_unref(builder); + + [super dealloc]; +} + +/* Presence handling */ +static gboolean refilter_roster(gpointer data) +{ + gtk_tree_model_filter_refilter(data); + + return FALSE; +} + +- (void)connection: (XMPPConnection*)connection + didReceivePresence: (XMPPPresence*)presence +{ + if ([presence.type isEqual: @"available"]) + [presences addObject: [presence.from bareJID]]; + else if ([presence.type isEqual: @"unavailable"]) + [presences removeObject: [presence.from bareJID]]; + + g_idle_add(refilter_roster, roster_filter); +} + +/* Roster Delegate methods */ +struct add_roster_item_param { + OFString *group; + OFString *name; + OFString *jid; + OFMapTable *groupMap; + OFMapTable *contactRows; + GtkTreeStore *roster_model; +}; + +static gboolean add_roster_item(gpointer user_data) +{ + struct add_roster_item_param *params = user_data; + GtkTreeIter group_iter, contact_iter; + GtkTreeRowReference *group_ref, *contact_ref; + GtkTreePath *group_path, *contact_path; + + group_ref = [params->groupMap valueForKey: params->group]; + + if (!group_ref) { + // Create new group row + gtk_tree_store_append(params->roster_model, &group_iter, NULL); + gtk_tree_store_set(params->roster_model, &group_iter, + 0, [params->group UTF8String], -1); + + group_path = gtk_tree_model_get_path(GTK_TREE_MODEL( + params->roster_model), &group_iter); + + group_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL( + params->roster_model), group_path); + + [params->groupMap setValue: group_ref + forKey: params->group]; + } else { + // Get iter for existing group row + group_path = gtk_tree_row_reference_get_path(group_ref); + + gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model), + &group_iter, group_path); + } + gtk_tree_path_free(group_path); + + // Create new contact row + gtk_tree_store_append(params->roster_model, &contact_iter, &group_iter); + gtk_tree_store_set(params->roster_model, &contact_iter, + 0, [params->name UTF8String], 1, [params->jid UTF8String], -1); + + contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL( + params->roster_model), &contact_iter); + + contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL( + params->roster_model), contact_path); + + gtk_tree_path_free(contact_path); + + [params->contactRows setValue: contact_ref + forKey: params->group]; + + [params->group release]; + [params->name release]; + [params->jid release]; + [params->groupMap release]; + [params->contactRows release]; + g_object_unref(params->roster_model); + free(params); + + return FALSE; +} + +struct remove_roster_item_param { + OFString *group; + OFMapTable *groupMap; + OFMapTable *contactRows; + GtkTreeStore *roster_model; +}; + +static gboolean remove_roster_item(gpointer user_data) +{ + struct remove_roster_item_param *params = user_data; + GtkTreeIter contact_iter, group_iter; + GtkTreePath *contact_path, *group_path; + GtkTreeRowReference *contact_ref, *group_ref; + + contact_ref = [params->contactRows valueForKey: params->group]; + contact_path = gtk_tree_row_reference_get_path(contact_ref); + gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model), + &contact_iter, contact_path); + + gtk_tree_store_remove(params->roster_model, &contact_iter); + + group_ref = [params->groupMap valueForKey: params->group]; + group_path = gtk_tree_row_reference_get_path(group_ref); + gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model), + &group_iter, group_path); + + if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(params->roster_model), + &group_iter)) { + gtk_tree_store_remove(params->roster_model, &group_iter); + [params->groupMap removeValueForKey: params->group]; + } + + gtk_tree_path_free(group_path); + + [params->group release]; + [params->groupMap release]; + [params->contactRows release]; + g_object_unref(params->roster_model); + free(params); + + return FALSE; +} + +- (void)rosterWasReceived: (XMPPRoster*)roster_ +{ + of_log(@"Handling roster"); + [[roster_ rosterItems] enumerateKeysAndObjectsUsingBlock: + ^(OFString *bareJID, XMPPRosterItem *item, BOOL *stop) { + OFArray *groups; + OFMapTable *contactRows = [OFMapTable + mapTableWithKeyFunctions: keyFunctions + valueFunctions: rowRefFunctions]; + + [contactMap setObject: contactRows + forKey: bareJID]; + + if (item.groups != nil) + groups = item.groups; + else + groups = @[@"General"]; + + for (OFString *group in groups) { + struct add_roster_item_param *params = + malloc(sizeof(*params)); + params->group = [group retain]; + params->name = [item.name retain]; + params->jid = [bareJID retain]; + params->groupMap = [groupMap retain]; + params->contactRows = [contactRows retain]; + params->roster_model = g_object_ref(roster_model); + g_idle_add(add_roster_item, params); + } + }]; +} + +- (void)roster: (XMPPRoster*)roster_ + didReceiveRosterItem: (XMPPRosterItem*)item +{ + OFArray *groups; + XMPPRosterItem *oldItem = + [roster_.rosterItems objectForKey: [item.JID bareJID]]; + + if (oldItem) { + if (oldItem.groups != nil) + groups = oldItem.groups; + else + groups = @[@"General"]; + + for (OFString *group in groups) { + struct remove_roster_item_param *params = + malloc(sizeof(*params)); + params->group = [group retain]; + params->contactRows = [[contactMap objectForKey: + [oldItem.JID bareJID]] retain]; + params->groupMap = [groupMap retain]; + params->roster_model = g_object_ref(roster_model); + g_idle_add(remove_roster_item, params); + } + + [contactMap removeObjectForKey: [item.JID bareJID]]; + } + + if (![item.subscription isEqual: @"remove"]) { + OFMapTable *contactRows = [OFMapTable + mapTableWithKeyFunctions: keyFunctions + valueFunctions: rowRefFunctions]; + + [contactMap setObject: contactRows + forKey: [item.JID bareJID]]; + + if (item.groups != nil) + groups = item.groups; + else + groups = @[@"General"]; + + for (OFString *group in groups) { + struct add_roster_item_param *params = + malloc(sizeof(*params)); + params->group = [group retain]; + params->name = [item.name retain]; + params->jid = [[item.JID bareJID] retain]; + params->groupMap = [groupMap retain]; + params->contactRows = [contactRows retain]; + params->roster_model = g_object_ref(roster_model); + g_idle_add(add_roster_item, params); + } + } +} + +@end diff --git a/src/gui/gtk/JubGtkUI.h b/src/gui/gtk/JubGtkUI.h index 1548194..a739e1a 100644 --- a/src/gui/gtk/JubGtkUI.h +++ b/src/gui/gtk/JubGtkUI.h @@ -3,12 +3,11 @@ #import "JubUI.h" -@interface JubGtkUI: OFObject +@class JubGtkRosterUI; + +@interface JubGtkUI: OFObject { - GtkTreeStore *roster_model; - GtkTreeModelFilter *roster_filter; - OFMapTable *groupMap; - OFMutableDictionary *contactMap; - OFCountedSet *presences; + JubGtkRosterUI *rosterUI; + GtkBuilder *builder; } @end diff --git a/src/gui/gtk/JubGtkUI.m b/src/gui/gtk/JubGtkUI.m index 359f483..000b483 100644 --- a/src/gui/gtk/JubGtkUI.m +++ b/src/gui/gtk/JubGtkUI.m @@ -2,50 +2,31 @@ #include #import "JubGtkUI.h" -#import "JubGObjectMap.h" +#import "JubGtkRosterUI.h" void on_roster_window_destroy(GObject *object, gpointer user_data) { gtk_main_quit(); } -static gboolean filter_roster_by_presence(GtkTreeModel *model, - GtkTreeIter *iter, gpointer data) -{ - char *jid_s; - OFString *jid; - OFCountedSet *presences = data; - - gtk_tree_model_get(model, iter, 1, &jid_s, -1); - - // Groups have no JID - if (!jid_s) - return TRUE; - - jid = [[OFString alloc] initWithUTF8String: jid_s]; - - g_free(jid_s); - - if ([presences countForObject: jid]) { - [jid release]; - return TRUE; - } else { - [jid release]; - return FALSE; - } -} - @implementation JubGtkUI - init { self = [super init]; @try { - groupMap = [[OFMapTable alloc] - initWithKeyFunctions: keyFunctions - valueFunctions: rowRefFunctions]; - contactMap = [[OFMutableDictionary alloc] init]; - presences = [[OFCountedSet alloc] init]; + int *argc; + char ***argv; + + [[OFApplication sharedApplication] getArgumentCount: &argc + andArgumentValues: &argv]; + + gtk_init(argc, argv); + + builder = gtk_builder_new(); + gtk_builder_add_from_file(builder, "data/gtk/roster.ui", NULL); + + rosterUI = [[JubGtkRosterUI alloc] initWithBuilder: builder]; } @catch (id e) { [self release]; @throw e; @@ -56,47 +37,20 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, - (void)dealloc { - - [groupMap release]; - [contactMap release]; - [presences release]; - - if (roster_model) - g_object_unref(roster_model); + [rosterUI release]; + g_object_unref(G_OBJECT(builder)); [super dealloc]; } - (void)startUIThread { - int *argc; - char ***argv; - - GtkBuilder *builder; GtkWidget *roster_window; - [[OFApplication sharedApplication] getArgumentCount: &argc - andArgumentValues: &argv]; - - gtk_init(argc, argv); - - builder = gtk_builder_new(); - gtk_builder_add_from_file(builder, "data/gtk/roster.ui", NULL); - roster_window = GTK_WIDGET(gtk_builder_get_object(builder, "RosterWindow")); - roster_model = - GTK_TREE_STORE(gtk_builder_get_object(builder, "RosterTreeStore")); - - roster_filter = GTK_TREE_MODEL_FILTER( - gtk_builder_get_object(builder,"RosterTreeModelFilter")); - - gtk_tree_model_filter_set_visible_func(roster_filter, - filter_roster_by_presence, presences, NULL); - gtk_builder_connect_signals(builder, NULL); - g_object_unref(G_OBJECT(builder)); gtk_widget_show(roster_window); @@ -108,225 +62,8 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, }] start]; } - - (id)rosterDelegate { - return self; -} - -/* Presence handling */ -static gboolean refilter_roster(gpointer data) -{ - gtk_tree_model_filter_refilter(data); - - return FALSE; -} - -- (void)connection: (XMPPConnection*)connection - didReceivePresence: (XMPPPresence*)presence -{ - if ([presence.type isEqual: @"available"]) - [presences addObject: [presence.from bareJID]]; - else - [presences removeObject: [presence.from bareJID]]; - - g_idle_add(refilter_roster, roster_filter); -} - -/* Roster Delegate methods */ -struct add_roster_item_param { - OFString *group; - OFString *name; - OFString *jid; - OFMapTable *groupMap; - OFMapTable *contactRows; - GtkTreeStore *roster_model; -}; - -static gboolean add_roster_item(gpointer user_data) -{ - struct add_roster_item_param *params = user_data; - GtkTreeIter group_iter, contact_iter; - GtkTreeRowReference *group_ref, *contact_ref; - GtkTreePath *group_path, *contact_path; - - group_ref = [params->groupMap valueForKey: params->group]; - - if (!group_ref) { - // Create new group row - gtk_tree_store_append(params->roster_model, &group_iter, NULL); - gtk_tree_store_set(params->roster_model, &group_iter, - 0, [params->group UTF8String], -1); - - group_path = gtk_tree_model_get_path(GTK_TREE_MODEL( - params->roster_model), &group_iter); - - group_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL( - params->roster_model), group_path); - - [params->groupMap setValue: group_ref - forKey: params->group]; - } else { - // Get iter for existing group row - group_path = gtk_tree_row_reference_get_path(group_ref); - - gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model), - &group_iter, group_path); - } - gtk_tree_path_free(group_path); - - // Create new contact row - gtk_tree_store_append(params->roster_model, &contact_iter, &group_iter); - gtk_tree_store_set(params->roster_model, &contact_iter, - 0, [params->name UTF8String], 1, [params->jid UTF8String], -1); - - contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL( - params->roster_model), &contact_iter); - - contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL( - params->roster_model), contact_path); - - gtk_tree_path_free(contact_path); - - [params->contactRows setValue: contact_ref - forKey: params->group]; - - [params->group release]; - [params->name release]; - [params->jid release]; - [params->groupMap release]; - [params->contactRows release]; - g_object_unref(params->roster_model); - free(params); - - return FALSE; -} - -struct remove_roster_item_param { - OFString *group; - OFMapTable *groupMap; - OFMapTable *contactRows; - GtkTreeStore *roster_model; -}; - -static gboolean remove_roster_item(gpointer user_data) -{ - struct remove_roster_item_param *params = user_data; - GtkTreeIter contact_iter, group_iter; - GtkTreePath *contact_path, *group_path; - GtkTreeRowReference *contact_ref, *group_ref; - - contact_ref = [params->contactRows valueForKey: params->group]; - contact_path = gtk_tree_row_reference_get_path(contact_ref); - gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model), - &contact_iter, contact_path); - - gtk_tree_store_remove(params->roster_model, &contact_iter); - - group_ref = [params->groupMap valueForKey: params->group]; - group_path = gtk_tree_row_reference_get_path(group_ref); - gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model), - &group_iter, group_path); - - if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(params->roster_model), - &group_iter)) { - gtk_tree_store_remove(params->roster_model, &group_iter); - [params->groupMap removeValueForKey: params->group]; - } - - gtk_tree_path_free(group_path); - - [params->group release]; - [params->groupMap release]; - [params->contactRows release]; - g_object_unref(params->roster_model); - free(params); - - return FALSE; -} - -- (void)rosterWasReceived: (XMPPRoster*)roster_ -{ - [[roster_ rosterItems] enumerateKeysAndObjectsUsingBlock: - ^(OFString *bareJID, XMPPRosterItem *item, BOOL *stop) { - OFArray *groups; - OFMapTable *contactRows = [OFMapTable - mapTableWithKeyFunctions: keyFunctions - valueFunctions: rowRefFunctions]; - - [contactMap setObject: contactRows - forKey: bareJID]; - - if (item.groups != nil) - groups = item.groups; - else - groups = @[@"General"]; - - for (OFString *group in groups) { - struct add_roster_item_param *params = - malloc(sizeof(*params)); - params->group = [group retain]; - params->name = [item.name retain]; - params->jid = [bareJID retain]; - params->groupMap = [groupMap retain]; - params->contactRows = [contactRows retain]; - params->roster_model = g_object_ref(roster_model); - g_idle_add(add_roster_item, params); - } - }]; -} - -- (void)roster: (XMPPRoster*)roster_ - didReceiveRosterItem: (XMPPRosterItem*)item -{ - OFArray *groups; - XMPPRosterItem *oldItem = - [roster_.rosterItems objectForKey: [item.JID bareJID]]; - - if (oldItem) { - if (oldItem.groups != nil) - groups = oldItem.groups; - else - groups = @[@"General"]; - - for (OFString *group in groups) { - struct remove_roster_item_param *params = - malloc(sizeof(*params)); - params->group = [group retain]; - params->contactRows = [[contactMap objectForKey: - [oldItem.JID bareJID]] retain]; - params->groupMap = [groupMap retain]; - params->roster_model = g_object_ref(roster_model); - g_idle_add(remove_roster_item, params); - } - - [contactMap removeObjectForKey: [item.JID bareJID]]; - } - - if (![item.subscription isEqual: @"remove"]) { - OFMapTable *contactRows = [OFMapTable - mapTableWithKeyFunctions: keyFunctions - valueFunctions: rowRefFunctions]; - - [contactMap setObject: contactRows - forKey: [item.JID bareJID]]; - - if (item.groups != nil) - groups = item.groups; - else - groups = @[@"General"]; - - for (OFString *group in groups) { - struct add_roster_item_param *params = - malloc(sizeof(*params)); - params->group = [group retain]; - params->name = [item.name retain]; - params->jid = [[item.JID bareJID] retain]; - params->groupMap = [groupMap retain]; - params->contactRows = [contactRows retain]; - params->roster_model = g_object_ref(roster_model); - g_idle_add(add_roster_item, params); - } - } + return rosterUI; } @end -- 2.39.5