]> cgit.babelmonkeys.de Git - jubjub.git/blobdiff - src/gui/gtk/JubGtkRosterUI.m
Move away from BOOL
[jubjub.git] / src / gui / gtk / JubGtkRosterUI.m
index 667760b0734cff566e6f9ed3a23791cc6340159b..432677cb8f1e2c9e92cbebf6efb29f2329931188 100644 (file)
@@ -32,7 +32,7 @@ static void roster_row_activated(GtkTreeView *tree_view, GtkTreePath *path,
 
        [client performSelectorOnMainThread: @selector(chatForContact:)
                                 withObject: contact
-                             waitUntilDone: NO];
+                             waitUntilDone: false];
        [pool release];
 }
 
@@ -50,6 +50,7 @@ static void presence_changed(GtkComboBox *combo_box, gpointer data)
 static gboolean filter_roster_by_presence(GtkTreeModel *model,
     GtkTreeIter *iter, gpointer data)
 {
+       bool *showOffline = data;
        char *status;
        gtk_tree_model_get(model, iter, 2, &status, -1);
 
@@ -57,24 +58,42 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
        if (!status)
                return TRUE;
 
-       if (!strcmp(status, "unavailable"))
+       if (!*showOffline && !strcmp(status, "unavailable"))
                return FALSE;
 
        return TRUE;
 }
 
+static void menu_show_offline(GtkCheckMenuItem *checkmenuitem, gpointer data)
+{
+       JubGtkRosterUI *ui = data;
+       ui.showOffline = gtk_check_menu_item_get_active(checkmenuitem);
+}
+
+static void dialog_response_callback(GtkDialog *dialog, gint response_id,
+    gpointer user_data)
+{
+       void (^block)(gint) = user_data;
+       block(response_id);
+       [block release];
+}
+
 @implementation JubGtkRosterUI
 - initWithClient: (JubChatClient*)client
 {
        self = [super init];
 
        @try {
+               GtkCheckMenuItem *show_offline_menu_item;
                GtkTreeView *roster_view;
                GtkBuilder *builder;
 
                _groupMap = [[OFMapTable alloc]
                    initWithKeyFunctions: keyFunctions
                          valueFunctions: rowRefFunctions];
+               _subDialogMap = [[OFMapTable alloc]
+                   initWithKeyFunctions: keyFunctions
+                   valueFunctions: gObjectFunctions];
                _contactMap = [[OFMutableDictionary alloc] init];
                _client = [client retain];
 
@@ -97,7 +116,7 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
                    gtk_builder_get_object(builder, "RosterTreeModelFilter"));
 
                gtk_tree_model_filter_set_visible_func(_roster_filter,
-                   filter_roster_by_presence, NULL, NULL);
+                   filter_roster_by_presence, &_showOffline, NULL);
 
                roster_view = GTK_TREE_VIEW(gtk_builder_get_object(builder,
                        "RosterTreeView"));
@@ -112,6 +131,13 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
                    g_signal_connect(_presence_combo, "changed",
                        G_CALLBACK(presence_changed), client);
 
+               show_offline_menu_item =
+                   GTK_CHECK_MENU_ITEM(gtk_builder_get_object(builder,
+                       "showOfflineCheckMenuItem"));
+
+               g_signal_connect(show_offline_menu_item, "toggled",
+                   G_CALLBACK(menu_show_offline), self);
+
                g_object_unref(G_OBJECT(builder));
        } @catch (id e) {
                [self release];
@@ -125,6 +151,7 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
 {
        [_client.avatarManager setDelegate: nil];
        [_client.contactManager removeDelegate: self];
+       [_subDialogMap release];
        [_groupMap release];
        [_contactMap release];
        [_client release];
@@ -134,6 +161,19 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
        [super dealloc];
 }
 
+- (void)Jub_closeSubscribeDialogForRosterItem: (XMPPRosterItem*)rosterItem
+{
+       // Close subscripton dialogs, answered on another client
+       GtkDialog *dialog;
+       OFString *subscription = rosterItem.subscription;
+       OFString *bareJID = [rosterItem.JID bareJID];
+
+       if (([subscription isEqual: @"from"] ||
+            [subscription isEqual: @"both"]) &&
+           (dialog = [_subDialogMap valueForKey: bareJID]) != NULL)
+               gtk_dialog_response(dialog, GTK_RESPONSE_NONE);
+}
+
 /* Roster Delegate methods */
 - (void)Jub_addRosterItem: (XMPPRosterItem*)item
                    group: (OFString*)group
@@ -257,6 +297,8 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
                    Jub_addRosterItem:group:)
                                       withObject: rosterItem
                                       withObject: group];
+
+       [self Jub_closeSubscribeDialogForRosterItem: rosterItem];
 }
 
 - (void)contactManager: (XMPPContactManager*)manager
@@ -275,9 +317,52 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
                                       withObject: group];
 }
 
+-          (void)contactManager: (XMPPContactManager*)manager
+  didReceiveSubscriptionRequest: (XMPPPresence*)presence
+{
+       XMPPJID *JID = presence.from;
+       OFString *bareJID = [JID bareJID];
+       OFString *message = [OFString stringWithFormat: @"<b>%@</b> would like "
+           @"to subscribe to your presence.", bareJID];
+       g_idle_add_block(^{
+               GtkWidget *dialog, *content_area, *label;
+
+               if ([_subDialogMap valueForKey: JID] != NULL)
+                       return;
+
+               dialog = gtk_dialog_new_with_buttons("Subscription Request",
+                   GTK_WINDOW(_roster_window), GTK_DIALOG_DESTROY_WITH_PARENT,
+                   "Accept", GTK_RESPONSE_ACCEPT,
+                   "Deny", GTK_RESPONSE_REJECT, NULL);
+
+               content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+               label = gtk_label_new(NULL);
+               gtk_label_set_markup(GTK_LABEL(label), [message UTF8String]);
+               gtk_container_add(GTK_CONTAINER(content_area), label);
+
+               g_signal_connect(dialog, "response",
+                   G_CALLBACK(dialog_response_callback),
+                   [^(gint response_id) {
+                       if (response_id == GTK_RESPONSE_ACCEPT)
+                               [manager sendSubscribedToJID: JID];
+                       else if (response_id == GTK_RESPONSE_REJECT)
+                               [manager sendUnsubscribedToJID: JID];
+                       [_subDialogMap removeValueForKey: bareJID];
+                       gtk_widget_destroy(GTK_WIDGET(dialog));
+               } copy]);
+
+               [_subDialogMap setValue: dialog
+                                forKey: bareJID];
+
+               gtk_widget_show_all(dialog);
+       });
+}
+
 -           (void)contact: (XMPPContact*)contact
   willUpdateWithRosterItem: (XMPPRosterItem*)rosterItem;
 {
+       [self Jub_closeSubscribeDialogForRosterItem: rosterItem];
+
        // Remove contact from old set of groups
        XMPPRosterItem *oldItem = contact.rosterItem;
        OFArray *groups = oldItem.groups;
@@ -380,7 +465,8 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
                OFArray *groups = contact.rosterItem.groups;;
 
                GdkPixbuf *avatar =
-                   gdk_pixbuf_new_from_file([avatarFile UTF8String], NULL);
+                   gdk_pixbuf_new_from_file_at_size([avatarFile UTF8String],
+                       32, 32, NULL);
 
                if (groups == nil)
                        groups = @[ @"General" ];
@@ -437,4 +523,17 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model,
                    [tooltip UTF8String]);
        });
 }
+
+- (bool)showOffline
+{
+       OF_GETTER(_showOffline, true);
+}
+
+- (void)setShowOffline: (bool)showOffline
+{
+       _showOffline = showOffline;
+       g_idle_add_block(^{
+               gtk_tree_model_filter_refilter(_roster_filter);
+       });
+}
 @end