From bea722223cba21d832750c78aee6ccf344400804 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sat, 15 Dec 2012 01:25:04 +0100 Subject: [PATCH] Filter roster model based on received presences --- data/gtk/roster.ui | 5 +- src/core/main.m | 10 +++- src/gui/common/JubUI.h | 2 +- src/gui/gtk/JubGtkUI.h | 4 +- src/gui/gtk/JubGtkUI.m | 115 ++++++++++++++++++++++++++++++----------- 5 files changed, 101 insertions(+), 35 deletions(-) diff --git a/data/gtk/roster.ui b/data/gtk/roster.ui index b2e05df..359de01 100644 --- a/data/gtk/roster.ui +++ b/data/gtk/roster.ui @@ -43,6 +43,9 @@ + + RosterTreeStore + False JubJub @@ -220,7 +223,7 @@ True True - RosterTreeStore + RosterTreeModelFilter 0 diff --git a/src/core/main.m b/src/core/main.m index e40a02f..ff97a3b 100644 --- a/src/core/main.m +++ b/src/core/main.m @@ -4,7 +4,7 @@ #import "JubGtkUI.h" @interface AppDelegate: OFObject - + { XMPPConnection *connection; XMPPRoster *roster; @@ -29,8 +29,11 @@ OF_APPLICATION_DELEGATE(AppDelegate) [connection connect]; [connection handleConnection]; + [connection addDelegate: [ui rosterDelegate]]; + roster = [[XMPPRoster alloc] initWithConnection: connection]; [roster addDelegate: [ui rosterDelegate]]; + [roster addDelegate: self]; [ui startUIThread]; } @@ -43,6 +46,11 @@ OF_APPLICATION_DELEGATE(AppDelegate) [roster requestRoster]; } +- (void)rosterWasReceived: (XMPPRoster*)roster +{ + [connection sendStanza: [XMPPPresence presence]]; +} + - (void)connection: (XMPPConnection*)conn didReceiveElement: (OFXMLElement*)element { diff --git a/src/gui/common/JubUI.h b/src/gui/common/JubUI.h index 3fd08b3..2ec2cf7 100644 --- a/src/gui/common/JubUI.h +++ b/src/gui/common/JubUI.h @@ -2,5 +2,5 @@ @protocol JubUI - (void)startUIThread; -- (id)rosterDelegate; +- (id)rosterDelegate; @end diff --git a/src/gui/gtk/JubGtkUI.h b/src/gui/gtk/JubGtkUI.h index 31e6902..1548194 100644 --- a/src/gui/gtk/JubGtkUI.h +++ b/src/gui/gtk/JubGtkUI.h @@ -3,10 +3,12 @@ #import "JubUI.h" -@interface JubGtkUI: OFObject +@interface JubGtkUI: OFObject { GtkTreeStore *roster_model; + GtkTreeModelFilter *roster_filter; OFMapTable *groupMap; OFMutableDictionary *contactMap; + OFCountedSet *presences; } @end diff --git a/src/gui/gtk/JubGtkUI.m b/src/gui/gtk/JubGtkUI.m index 48278b8..359f483 100644 --- a/src/gui/gtk/JubGtkUI.m +++ b/src/gui/gtk/JubGtkUI.m @@ -9,6 +9,32 @@ 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 { @@ -19,6 +45,7 @@ void on_roster_window_destroy(GObject *object, gpointer user_data) initWithKeyFunctions: keyFunctions valueFunctions: rowRefFunctions]; contactMap = [[OFMutableDictionary alloc] init]; + presences = [[OFCountedSet alloc] init]; } @catch (id e) { [self release]; @throw e; @@ -32,6 +59,7 @@ void on_roster_window_destroy(GObject *object, gpointer user_data) [groupMap release]; [contactMap release]; + [presences release]; if (roster_model) g_object_unref(roster_model); @@ -61,6 +89,12 @@ void on_roster_window_destroy(GObject *object, gpointer user_data) 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)); @@ -80,6 +114,25 @@ void on_roster_window_destroy(GObject *object, gpointer user_data) 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; @@ -149,37 +202,6 @@ static gboolean add_roster_item(gpointer user_data) 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); - } - }]; -} - struct remove_roster_item_param { OFString *group; OFMapTable *groupMap; @@ -223,6 +245,37 @@ static gboolean remove_roster_item(gpointer user_data) 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 { -- 2.39.2