Statistics
| Revision:

root / src / subscribedialog.c @ 2452

History | View | Annotate | Download (17.1 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 */
19
20
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include "defs.h"
25
26
#include <glib.h>
27
#include <glib/gi18n.h>
28
#include <gdk/gdkkeysyms.h>
29
#include <gtk/gtkmain.h>
30
#include <gtk/gtkwidget.h>
31
#include <gtk/gtkdialog.h>
32
#include <gtk/gtkwindow.h>
33
#include <gtk/gtksignal.h>
34
#include <gtk/gtkvbox.h>
35
#include <gtk/gtkhbox.h>
36
#include <gtk/gtklabel.h>
37
#include <gtk/gtkentry.h>
38
#include <gtk/gtktreestore.h>
39
#include <gtk/gtktreeview.h>
40
#include <gtk/gtktreeselection.h>
41
#include <gtk/gtkcellrenderertoggle.h>
42
#include <gtk/gtkcellrenderertext.h>
43
#include <gtk/gtkscrolledwindow.h>
44
#include <gtk/gtkbutton.h>
45
#include <gtk/gtkhbbox.h>
46
#include <gtk/gtkstock.h>
47
#include <string.h>
48
49
#include "subscribedialog.h"
50
#include "manage_window.h"
51
#include "mainwindow.h"
52
#include "gtkutils.h"
53
#include "utils.h"
54
#include "news.h"
55
#include "folder.h"
56
#include "alertpanel.h"
57
#include "statusbar.h"
58
#include "recv.h"
59
#include "socket.h"
60
61
enum {
62
        SUBSCRIBE_TOGGLE,
63
        SUBSCRIBE_NAME,
64
        SUBSCRIBE_NUM,
65
        SUBSCRIBE_TYPE,
66
        SUBSCRIBE_INFO,
67
        SUBSCRIBE_CAN_TOGGLE,
68
        N_SUBSCRIBE_COLUMNS
69
};
70
71
#define SUBSCRIBE_DIALOG_WIDTH                450
72
#define SUBSCRIBE_DIALOG_HEIGHT                400
73
#define SUBSCRIBE_COL_NAME_WIDTH        250
74
75
static gboolean ack;
76
static gboolean locked;
77
78
static GtkWidget *dialog;
79
static GtkWidget *entry;
80
static GtkWidget *treeview;
81
static GtkWidget *status_label;
82
static GtkWidget *ok_button;
83
84
static GtkTreeStore *tree_store;
85
86
static GSList *group_list;
87
static GSList *subscribe_list;
88
static Folder *news_folder;
89
90
static void subscribe_dialog_create        (void);
91
static void subscribe_dialog_set_list        (const gchar        *pattern,
92
                                         gboolean         refresh);
93
static void subscribe_search                (void);
94
static void subscribe_clear                (void);
95
96
static gboolean subscribe_recv_func        (SockInfo        *sock,
97
                                         gint                 count,
98
                                         gint                 read_bytes,
99
                                         gpointer         data);
100
101
static gint window_deleted        (GtkWidget        *widget,
102
                                 GdkEventAny        *event,
103
                                 gpointer         data);
104
static void ok_clicked                (GtkWidget        *widget,
105
                                 gpointer         data);
106
static void cancel_clicked        (GtkWidget        *widget,
107
                                 gpointer         data);
108
static void refresh_clicked        (GtkWidget        *widget,
109
                                 gpointer         data);
110
static gboolean key_pressed        (GtkWidget        *widget,
111
                                 GdkEventKey        *event,
112
                                 gpointer         data);
113
114
static gboolean subscribe_selected        (GtkTreeSelection        *selection,
115
                                         GtkTreeModel                *model,
116
                                         GtkTreePath                *path,
117
                                         gboolean                 cur_selected,
118
                                         gpointer                 data);
119
120
static void subscribe_toggled        (GtkCellRenderer        *cell,
121
                                 gchar                        *path,
122
                                 gpointer                 data);
123
124
static void entry_activated        (GtkEditable        *editable);
125
static void search_clicked        (GtkWidget        *widget,
126
                                 gpointer         data);
127
128
GSList *subscribe_dialog(Folder *folder)
129
{
130
        GNode *node;
131
        FolderItem *item;
132
133
        if (dialog && GTK_WIDGET_VISIBLE(dialog)) return NULL;
134
135
        if (!dialog)
136
                subscribe_dialog_create();
137
138
        news_folder = folder;
139
140
        gtk_widget_show(dialog);
141
        gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
142
        manage_window_set_transient(GTK_WINDOW(dialog));
143
        gtk_widget_grab_focus(ok_button);
144
        gtk_widget_grab_focus(treeview);
145
        GTK_EVENTS_FLUSH();
146
147
        subscribe_list = NULL;
148
        for (node = folder->node->children; node != NULL; node = node->next) {
149
                item = FOLDER_ITEM(node->data);
150
                subscribe_list = g_slist_append(subscribe_list,
151
                                                g_strdup(item->path));
152
        }
153
154
        subscribe_dialog_set_list(NULL, TRUE);
155
156
        if (ack) gtk_main();
157
158
        manage_window_focus_out(dialog, NULL, NULL);
159
        gtk_widget_hide(dialog);
160
        main_window_popup(main_window_get());
161
162
        if (ack) {
163
                GSList *cur;
164
165
                slist_free_strings(subscribe_list);
166
                subscribe_list = NULL;
167
                for (cur = group_list; cur != NULL; cur = cur->next) {
168
                        NewsGroupInfo *ginfo = (NewsGroupInfo *)cur->data;
169
170
                        if (ginfo->subscribed)
171
                                subscribe_list = g_slist_append
172
                                        (subscribe_list, g_strdup(ginfo->name));
173
                }
174
        }
175
176
        subscribe_clear();
177
178
        return subscribe_list;
179
}
180
181
static void subscribe_dialog_create(void)
182
{
183
        GtkWidget *vbox;
184
        GtkWidget *hbox;
185
        GtkWidget *msg_label;
186
        GtkWidget *search_button;
187
        GtkWidget *confirm_area;
188
        GtkWidget *cancel_button;        
189
        GtkWidget *refresh_button;        
190
        GtkWidget *scrolledwin;
191
        GtkTreeViewColumn *column;
192
        GtkCellRenderer *renderer;
193
        GtkTreeSelection *selection;
194
195
        dialog = gtk_dialog_new();
196
        gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, TRUE, FALSE);
197
        gtk_widget_set_size_request(dialog,
198
                                    SUBSCRIBE_DIALOG_WIDTH,
199
                                    SUBSCRIBE_DIALOG_HEIGHT);
200
        gtk_container_set_border_width
201
                (GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 5);
202
        gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
203
        gtk_window_set_title(GTK_WINDOW(dialog), _("Subscribe to newsgroup"));
204
        g_signal_connect(G_OBJECT(dialog), "delete_event",
205
                         G_CALLBACK(window_deleted), NULL);
206
        g_signal_connect(G_OBJECT(dialog), "key_press_event",
207
                         G_CALLBACK(key_pressed), NULL);
208
        MANAGE_WINDOW_SIGNALS_CONNECT(dialog);
209
210
        gtk_widget_realize(dialog);
211
212
        vbox = gtk_vbox_new(FALSE, 8);
213
        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
214
        gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
215
216
        hbox = gtk_hbox_new(FALSE, 0);
217
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
218
219
        msg_label = gtk_label_new(_("Select newsgroups to subscribe."));
220
        gtk_box_pack_start(GTK_BOX(hbox), msg_label, FALSE, FALSE, 0);
221
222
        hbox = gtk_hbox_new(FALSE, 8);
223
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
224
225
        msg_label = gtk_label_new(_("Find groups:"));
226
        gtk_box_pack_start(GTK_BOX(hbox), msg_label, FALSE, FALSE, 0);
227
228
        entry = gtk_entry_new();
229
        gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
230
        g_signal_connect(G_OBJECT(entry), "activate",
231
                         G_CALLBACK(entry_activated), NULL);
232
233
        search_button = gtk_button_new_with_label(_(" Search "));
234
        gtk_box_pack_start(GTK_BOX(hbox), search_button, FALSE, FALSE, 0);
235
236
        g_signal_connect(G_OBJECT(search_button), "clicked",
237
                         G_CALLBACK(search_clicked), NULL);
238
239
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
240
        gtk_box_pack_start(GTK_BOX (vbox), scrolledwin, TRUE, TRUE, 0);
241
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
242
                                       GTK_POLICY_AUTOMATIC,
243
                                       GTK_POLICY_AUTOMATIC);
244
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
245
                                            GTK_SHADOW_IN);
246
247
        tree_store = gtk_tree_store_new(N_SUBSCRIBE_COLUMNS,
248
                                        G_TYPE_BOOLEAN,
249
                                        G_TYPE_STRING,
250
                                        G_TYPE_STRING,
251
                                        G_TYPE_STRING,
252
                                        G_TYPE_POINTER,
253
                                        G_TYPE_BOOLEAN);
254
        gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(tree_store),
255
                                             SUBSCRIBE_NAME,
256
                                             GTK_SORT_ASCENDING);
257
258
        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store));
259
        g_object_unref(G_OBJECT(tree_store));
260
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
261
        gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview),
262
                                        SUBSCRIBE_NAME);
263
264
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
265
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
266
        gtk_tree_selection_set_select_function(selection, subscribe_selected,
267
                                               NULL, NULL);
268
269
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
270
271
        renderer = gtk_cell_renderer_toggle_new();
272
        column = gtk_tree_view_column_new_with_attributes
273
                (NULL, renderer, "active", SUBSCRIBE_TOGGLE,
274
                 "activatable", SUBSCRIBE_CAN_TOGGLE,
275
                 "visible", SUBSCRIBE_CAN_TOGGLE, NULL);
276
        gtk_tree_view_column_set_min_width(column, 20);
277
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
278
        g_signal_connect(renderer, "toggled", G_CALLBACK(subscribe_toggled),
279
                         NULL);
280
281
        renderer = gtk_cell_renderer_text_new();
282
        column = gtk_tree_view_column_new_with_attributes
283
                (_("Newsgroup name"), renderer, "text", SUBSCRIBE_NAME, NULL);
284
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
285
        gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
286
287
        renderer = gtk_cell_renderer_text_new();
288
        column = gtk_tree_view_column_new_with_attributes
289
                (_("Messages"), renderer, "text", SUBSCRIBE_NUM, NULL);
290
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
291
292
        renderer = gtk_cell_renderer_text_new();
293
        column = gtk_tree_view_column_new_with_attributes
294
                (_("Type"), renderer, "text", SUBSCRIBE_TYPE, NULL);
295
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
296
297
        hbox = gtk_hbox_new(FALSE, 0);
298
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
299
300
        status_label = gtk_label_new("");
301
        gtk_box_pack_start(GTK_BOX(hbox), status_label, FALSE, FALSE, 0);
302
303
        gtkut_stock_button_set_create(&confirm_area,
304
                                      &ok_button, GTK_STOCK_OK,
305
                                      &cancel_button, GTK_STOCK_CANCEL,
306
                                      &refresh_button, GTK_STOCK_REFRESH);
307
        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
308
                          confirm_area);
309
        gtk_widget_grab_default(ok_button);
310
311
        g_signal_connect(G_OBJECT(ok_button), "clicked",
312
                         G_CALLBACK(ok_clicked), NULL);
313
        g_signal_connect(G_OBJECT(cancel_button), "clicked",
314
                         G_CALLBACK(cancel_clicked), NULL);
315
        g_signal_connect(G_OBJECT(refresh_button), "clicked",
316
                         G_CALLBACK(refresh_clicked), NULL);
317
318
        gtk_widget_show_all(GTK_DIALOG(dialog)->vbox);
319
}
320
321
static GHashTable *branch_node_table;
322
323
static void subscribe_hash_init(void)
324
{
325
        branch_node_table = g_hash_table_new_full
326
                (g_str_hash, g_str_equal, NULL,
327
                 (GDestroyNotify)gtk_tree_iter_free);
328
}
329
330
static void subscribe_hash_free(void)
331
{
332
        hash_free_strings(branch_node_table);
333
        g_hash_table_destroy(branch_node_table);
334
}
335
336
static gboolean subscribe_hash_get_branch_node(const gchar *name,
337
                                               GtkTreeIter *iter)
338
{
339
        GtkTreeIter *iter_;
340
341
        iter_ = g_hash_table_lookup(branch_node_table, name);
342
        if (iter_) {
343
                *iter = *iter_;
344
                return TRUE;
345
        }
346
347
        return FALSE;
348
}
349
350
static void subscribe_hash_set_branch_node(const gchar *name,
351
                                           GtkTreeIter *iter)
352
{
353
        GtkTreeIter *iter_;
354
355
        iter_ = gtk_tree_iter_copy(iter);
356
        g_hash_table_replace(branch_node_table, g_strdup(name), iter_);
357
}
358
359
static gchar *subscribe_get_parent_name(const gchar *name)
360
{
361
        gchar *p;
362
363
        p = strrchr(name, '.');
364
        if (!p)
365
                return g_strdup("");
366
        return g_strndup(name, p - name);
367
}
368
369
static gboolean subscribe_create_parent(const gchar *name,
370
                                        const gchar *pattern,
371
                                        GtkTreeIter *parent)
372
{
373
        GtkTreeIter parent_;
374
        GtkTreeIter iter;
375
        gchar *parent_name;
376
        gboolean has_parent;
377
378
        if (*name == '\0') return FALSE;
379
        if (subscribe_hash_get_branch_node(name, &iter)) {
380
                *parent = iter;
381
                return TRUE;
382
        }
383
384
        parent_name = subscribe_get_parent_name(name);
385
        has_parent = subscribe_create_parent(parent_name, pattern, &parent_);
386
387
        if (has_parent) {
388
                gtk_tree_store_append(tree_store, &iter, &parent_);
389
                if (g_pattern_match_simple(pattern, parent_name) == FALSE)
390
                        gtkut_tree_view_expand_parent_all
391
                                (GTK_TREE_VIEW(treeview), &iter);
392
        } else
393
                gtk_tree_store_append(tree_store, &iter, NULL);
394
        gtk_tree_store_set(tree_store, &iter, SUBSCRIBE_NAME, name, -1);
395
396
        subscribe_hash_set_branch_node(name, &iter);
397
398
        g_free(parent_name);
399
400
        *parent = iter;
401
402
        return TRUE;
403
}
404
405
static gboolean subscribe_create_branch(NewsGroupInfo *ginfo,
406
                                        const gchar *pattern,
407
                                        GtkTreeIter *iter)
408
{
409
        GtkTreeIter iter_;
410
        GtkTreeIter parent;
411
        const gchar *name = ginfo->name;
412
        gchar *parent_name;
413
        gint count;
414
        const gchar *count_str;
415
        const gchar *type_str;
416
        gboolean has_parent;
417
418
        count = ginfo->last - ginfo->first;
419
        if (count < 0)
420
                count = 0;
421
        count_str = itos(count);
422
423
        if (ginfo->type == 'y')
424
                type_str = "";
425
        else if (ginfo->type == 'm')
426
                type_str = _("moderated");
427
        else if (ginfo->type == 'n')
428
                type_str = _("readonly");
429
        else
430
                type_str = _("unknown");
431
432
        parent_name = subscribe_get_parent_name(name);
433
        has_parent = subscribe_create_parent(parent_name, pattern, &parent);
434
        if (!subscribe_hash_get_branch_node(name, &iter_)) {
435
                if (has_parent) {
436
                        gtk_tree_store_append(tree_store, &iter_, &parent);
437
                        if (g_pattern_match_simple(pattern, parent_name) == FALSE)
438
                                gtkut_tree_view_expand_parent_all
439
                                        (GTK_TREE_VIEW(treeview), &iter_);
440
                } else
441
                        gtk_tree_store_append(tree_store, &iter_, NULL);
442
        }
443
444
        gtk_tree_store_set(tree_store, &iter_,
445
                           SUBSCRIBE_NAME, name,
446
                           SUBSCRIBE_NUM, count_str,
447
                           SUBSCRIBE_TYPE, type_str,
448
                           SUBSCRIBE_INFO, ginfo,
449
                           SUBSCRIBE_CAN_TOGGLE, TRUE,
450
                           -1);
451
452
        g_free(parent_name);
453
454
        *iter = iter_;
455
456
        return TRUE;
457
}
458
459
static void subscribe_dialog_set_list(const gchar *pattern, gboolean refresh)
460
{
461
        gchar *pattern_;
462
        GSList *cur;
463
        GPatternSpec *pspec;
464
465
        if (locked) return;
466
        locked = TRUE;
467
468
        if (!pattern || *pattern == '\0')
469
                pattern_ = g_strdup("*");
470
        else if (strchr(pattern, '*') == NULL)
471
                pattern_ = g_strconcat("*", pattern, "*", NULL);
472
        else
473
                pattern_ = g_strdup(pattern);
474
475
        if (refresh) {
476
                ack = TRUE;
477
                subscribe_clear();
478
                if (pattern)
479
                        gtk_entry_set_text(GTK_ENTRY(entry), pattern);
480
                gtk_label_set_text(GTK_LABEL(status_label),
481
                                   _("Getting newsgroup list..."));
482
                GTK_EVENTS_FLUSH();
483
                recv_set_ui_func(subscribe_recv_func, NULL);
484
                group_list = news_get_group_list(news_folder);
485
                group_list = g_slist_reverse(group_list);
486
                recv_set_ui_func(NULL, NULL);
487
                statusbar_pop_all();
488
                if (group_list == NULL && ack == TRUE) {
489
                        alertpanel_error(_("Can't retrieve newsgroup list."));
490
                        g_free(pattern_);
491
                        locked = FALSE;
492
                        return;
493
                }
494
        } else {
495
                gtk_tree_store_clear(tree_store);
496
        }
497
498
        subscribe_hash_init();
499
500
        pspec = g_pattern_spec_new(pattern_);
501
502
        for (cur = group_list; cur != NULL ; cur = cur->next) {
503
                NewsGroupInfo *ginfo = (NewsGroupInfo *)cur->data;
504
                GtkTreeIter iter;
505
506
                if (!ginfo->name || !is_ascii_str(ginfo->name))
507
                        continue;
508
509
                if (g_slist_find_custom(subscribe_list, ginfo->name,
510
                                        (GCompareFunc)g_ascii_strcasecmp)
511
                    != NULL)
512
                        ginfo->subscribed = TRUE;
513
514
                if (g_pattern_match_string(pspec, ginfo->name)) {
515
                        subscribe_create_branch(ginfo, pattern_, &iter);
516
                        if (ginfo->subscribed)
517
                                gtk_tree_store_set(tree_store, &iter,
518
                                                   SUBSCRIBE_TOGGLE, TRUE, -1);
519
                }
520
        }
521
522
        g_pattern_spec_free(pspec);
523
        subscribe_hash_free();
524
        g_free(pattern_);
525
526
        gtk_label_set_text(GTK_LABEL(status_label), _("Done."));
527
528
        locked = FALSE;
529
}
530
531
static void subscribe_search(void)
532
{
533
        gchar *str;
534
535
        if (locked) return;
536
537
        str = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
538
        subscribe_dialog_set_list(str, FALSE);
539
        g_free(str);
540
}
541
542
static void subscribe_clear(void)
543
{
544
        gtk_tree_store_clear(tree_store);
545
        gtk_entry_set_text(GTK_ENTRY(entry), "");
546
        news_group_list_free(group_list);
547
        group_list = NULL;
548
}
549
550
static gboolean subscribe_recv_func(SockInfo *sock, gint count, gint read_bytes,
551
                                    gpointer data)
552
{
553
        gchar buf[BUFFSIZE];
554
555
        g_snprintf(buf, sizeof(buf),
556
                   _("%d newsgroups received (%s read)"),
557
                   count, to_human_readable(read_bytes));
558
        gtk_label_set_text(GTK_LABEL(status_label), buf);
559
        GTK_EVENTS_FLUSH();
560
        if (ack == FALSE)
561
                return FALSE;
562
        else
563
                return TRUE;
564
}
565
566
static gint window_deleted(GtkWidget *widget, GdkEventAny *event, gpointer data)
567
{
568
        ack = FALSE;
569
        if (gtk_main_level() > 1)
570
                gtk_main_quit();
571
572
        return TRUE;
573
}
574
575
static void ok_clicked(GtkWidget *widget, gpointer data)
576
{
577
        ack = TRUE;
578
        if (gtk_main_level() > 1)
579
                gtk_main_quit();
580
}
581
582
static void cancel_clicked(GtkWidget *widget, gpointer data)
583
{
584
        ack = FALSE;
585
        if (gtk_main_level() > 1)
586
                gtk_main_quit();
587
}
588
589
static void refresh_clicked(GtkWidget *widget, gpointer data)
590
{ 
591
        gchar *str;
592
593
        if (locked) return;
594
595
        news_remove_group_list_cache(news_folder);
596
597
        str = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
598
        subscribe_dialog_set_list(str, TRUE);
599
        g_free(str);
600
}
601
602
static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
603
                            gpointer data)
604
{
605
        if (event && event->keyval == GDK_Escape)
606
                cancel_clicked(NULL, NULL);
607
        return FALSE;
608
}
609
610
static gboolean subscribe_selected(GtkTreeSelection *selection,
611
                                   GtkTreeModel *model, GtkTreePath *path,
612
                                   gboolean cur_selected, gpointer data)
613
{
614
        GtkTreeIter iter;
615
        NewsGroupInfo *ginfo;
616
617
        if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store), &iter, path))
618
                return FALSE;
619
620
        gtk_tree_model_get(GTK_TREE_MODEL(tree_store), &iter,
621
                           SUBSCRIBE_INFO, &ginfo, -1);
622
        if (!ginfo)
623
                return FALSE;
624
625
        return TRUE;
626
}
627
628
static void subscribe_toggled(GtkCellRenderer *cell, gchar *path_str,
629
                              gpointer data)
630
{
631
        GtkTreePath *path;
632
        GtkTreeIter iter;
633
        gboolean enabled;
634
        NewsGroupInfo *ginfo;
635
        gboolean can_toggle;
636
637
        path = gtk_tree_path_new_from_string(path_str);
638
        gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store), &iter, path);
639
        gtk_tree_path_free(path);
640
641
        gtk_tree_model_get(GTK_TREE_MODEL(tree_store), &iter,
642
                           SUBSCRIBE_TOGGLE, &enabled,
643
                           SUBSCRIBE_INFO, &ginfo,
644
                           SUBSCRIBE_CAN_TOGGLE, &can_toggle,
645
                           -1);
646
        if (ginfo && can_toggle) {
647
                ginfo->subscribed = !enabled;
648
                gtk_tree_store_set(tree_store, &iter,
649
                                   SUBSCRIBE_TOGGLE, !enabled, -1);
650
        }
651
}
652
653
static void entry_activated(GtkEditable *editable)
654
{
655
        subscribe_search();
656
}
657
658
static void search_clicked(GtkWidget *widget, gpointer data)
659
{
660
        subscribe_search();
661
}