1 #import "JubGtkRosterUI.h"
2 #import "JubGObjectMap.h"
4 static gboolean filter_roster_by_presence(GtkTreeModel *model,
5 GtkTreeIter *iter, gpointer data)
9 OFCountedSet *presences = data;
11 gtk_tree_model_get(model, iter, 1, &jid_s, -1);
17 jid = [[OFString alloc] initWithUTF8String: jid_s];
21 int num = [presences countForObject: jid];
31 @implementation JubGtkRosterUI
32 - initWithBuilder: (GtkBuilder*)builder_
37 groupMap = [[OFMapTable alloc]
38 initWithKeyFunctions: keyFunctions
39 valueFunctions: rowRefFunctions];
40 contactMap = [[OFMutableDictionary alloc] init];
41 presences = [[OFCountedSet alloc] init];
43 builder = g_object_ref(builder_);
45 roster_model = GTK_TREE_STORE(gtk_builder_get_object(builder,
48 roster_filter = GTK_TREE_MODEL_FILTER(
49 gtk_builder_get_object(builder, "RosterTreeModelFilter"));
51 gtk_tree_model_filter_set_visible_func(roster_filter,
52 filter_roster_by_presence, presences, NULL);
68 g_object_unref(roster_model);
71 g_object_unref(roster_filter);
73 g_object_unref(builder);
78 /* Presence handling */
79 static gboolean refilter_roster(gpointer data)
81 gtk_tree_model_filter_refilter(data);
86 - (void)connection: (XMPPConnection*)connection
87 didReceivePresence: (XMPPPresence*)presence
89 if ([presence.type isEqual: @"available"])
90 [presences addObject: [presence.from bareJID]];
91 else if ([presence.type isEqual: @"unavailable"])
92 [presences removeObject: [presence.from bareJID]];
94 g_idle_add(refilter_roster, roster_filter);
97 /* Roster Delegate methods */
98 struct add_roster_item_param {
102 OFMapTable *groupMap;
103 OFMapTable *contactRows;
104 GtkTreeStore *roster_model;
107 static gboolean add_roster_item(gpointer user_data)
109 struct add_roster_item_param *params = user_data;
110 GtkTreeIter group_iter, contact_iter;
111 GtkTreeRowReference *group_ref, *contact_ref;
112 GtkTreePath *group_path, *contact_path;
114 group_ref = [params->groupMap valueForKey: params->group];
117 // Create new group row
118 gtk_tree_store_append(params->roster_model, &group_iter, NULL);
119 gtk_tree_store_set(params->roster_model, &group_iter,
120 0, [params->group UTF8String], -1);
122 group_path = gtk_tree_model_get_path(GTK_TREE_MODEL(
123 params->roster_model), &group_iter);
125 group_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(
126 params->roster_model), group_path);
128 [params->groupMap setValue: group_ref
129 forKey: params->group];
131 // Get iter for existing group row
132 group_path = gtk_tree_row_reference_get_path(group_ref);
134 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
135 &group_iter, group_path);
137 gtk_tree_path_free(group_path);
139 // Create new contact row
140 gtk_tree_store_append(params->roster_model, &contact_iter, &group_iter);
141 gtk_tree_store_set(params->roster_model, &contact_iter,
142 0, [params->name UTF8String], 1, [params->jid UTF8String], -1);
144 contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL(
145 params->roster_model), &contact_iter);
147 contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(
148 params->roster_model), contact_path);
150 gtk_tree_path_free(contact_path);
152 [params->contactRows setValue: contact_ref
153 forKey: params->group];
155 [params->group release];
156 [params->name release];
157 [params->jid release];
158 [params->groupMap release];
159 [params->contactRows release];
160 g_object_unref(params->roster_model);
166 struct remove_roster_item_param {
168 OFMapTable *groupMap;
169 OFMapTable *contactRows;
170 GtkTreeStore *roster_model;
173 static gboolean remove_roster_item(gpointer user_data)
175 struct remove_roster_item_param *params = user_data;
176 GtkTreeIter contact_iter, group_iter;
177 GtkTreePath *contact_path, *group_path;
178 GtkTreeRowReference *contact_ref, *group_ref;
180 contact_ref = [params->contactRows valueForKey: params->group];
181 contact_path = gtk_tree_row_reference_get_path(contact_ref);
182 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
183 &contact_iter, contact_path);
185 gtk_tree_store_remove(params->roster_model, &contact_iter);
187 group_ref = [params->groupMap valueForKey: params->group];
188 group_path = gtk_tree_row_reference_get_path(group_ref);
189 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
190 &group_iter, group_path);
192 if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(params->roster_model),
194 gtk_tree_store_remove(params->roster_model, &group_iter);
195 [params->groupMap removeValueForKey: params->group];
198 gtk_tree_path_free(group_path);
200 [params->group release];
201 [params->groupMap release];
202 [params->contactRows release];
203 g_object_unref(params->roster_model);
209 - (void)rosterWasReceived: (XMPPRoster*)roster_
211 of_log(@"Handling roster");
212 [[roster_ rosterItems] enumerateKeysAndObjectsUsingBlock:
213 ^(OFString *bareJID, XMPPRosterItem *item, BOOL *stop) {
215 OFMapTable *contactRows = [OFMapTable
216 mapTableWithKeyFunctions: keyFunctions
217 valueFunctions: rowRefFunctions];
219 [contactMap setObject: contactRows
222 if (item.groups != nil)
223 groups = item.groups;
225 groups = @[@"General"];
227 for (OFString *group in groups) {
228 struct add_roster_item_param *params =
229 malloc(sizeof(*params));
230 params->group = [group retain];
231 params->name = [item.name retain];
232 params->jid = [bareJID retain];
233 params->groupMap = [groupMap retain];
234 params->contactRows = [contactRows retain];
235 params->roster_model = g_object_ref(roster_model);
236 g_idle_add(add_roster_item, params);
241 - (void)roster: (XMPPRoster*)roster_
242 didReceiveRosterItem: (XMPPRosterItem*)item
245 XMPPRosterItem *oldItem =
246 [roster_.rosterItems objectForKey: [item.JID bareJID]];
249 if (oldItem.groups != nil)
250 groups = oldItem.groups;
252 groups = @[@"General"];
254 for (OFString *group in groups) {
255 struct remove_roster_item_param *params =
256 malloc(sizeof(*params));
257 params->group = [group retain];
258 params->contactRows = [[contactMap objectForKey:
259 [oldItem.JID bareJID]] retain];
260 params->groupMap = [groupMap retain];
261 params->roster_model = g_object_ref(roster_model);
262 g_idle_add(remove_roster_item, params);
265 [contactMap removeObjectForKey: [item.JID bareJID]];
268 if (![item.subscription isEqual: @"remove"]) {
269 OFMapTable *contactRows = [OFMapTable
270 mapTableWithKeyFunctions: keyFunctions
271 valueFunctions: rowRefFunctions];
273 [contactMap setObject: contactRows
274 forKey: [item.JID bareJID]];
276 if (item.groups != nil)
277 groups = item.groups;
279 groups = @[@"General"];
281 for (OFString *group in groups) {
282 struct add_roster_item_param *params =
283 malloc(sizeof(*params));
284 params->group = [group retain];
285 params->name = [item.name retain];
286 params->jid = [[item.JID bareJID] retain];
287 params->groupMap = [groupMap retain];
288 params->contactRows = [contactRows retain];
289 params->roster_model = g_object_ref(roster_model);
290 g_idle_add(add_roster_item, params);