Statistics
| Revision:

root / src / subscribedialog.c @ 2411

History | View | Annotate | Download (17.1 kB)

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