Statistics
| Revision:

root / src / folderview.c @ 366

History | View | Annotate | Download (70.9 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
#include "defs.h"
21
22
#include <glib.h>
23
#include <glib/gi18n.h>
24
#include <gdk/gdkkeysyms.h>
25
#include <gtk/gtkwidget.h>
26
#include <gtk/gtkscrolledwindow.h>
27
#include <gtk/gtktreestore.h>
28
#include <gtk/gtktreeview.h>
29
#include <gtk/gtktreeselection.h>
30
#include <gtk/gtkcellrendererpixbuf.h>
31
#include <gtk/gtkcellrenderertext.h>
32
#include <gtk/gtksignal.h>
33
#include <gtk/gtkmain.h>
34
#include <gtk/gtkstatusbar.h>
35
#include <gtk/gtkmenu.h>
36
#include <gtk/gtkmenuitem.h>
37
#include <gtk/gtkitemfactory.h>
38
#include <gtk/gtkstock.h>
39
#include <gtk/gtkversion.h>
40
#include <stdio.h>
41
#include <string.h>
42
#include <stdlib.h>
43
44
#include "main.h"
45
#include "mainwindow.h"
46
#include "folderview.h"
47
#include "summaryview.h"
48
#include "summary_search.h"
49
#include "inputdialog.h"
50
#include "grouplistdialog.h"
51
#include "manage_window.h"
52
#include "alertpanel.h"
53
#include "menu.h"
54
#include "stock_pixmap.h"
55
#include "statusbar.h"
56
#include "procmsg.h"
57
#include "utils.h"
58
#include "gtkutils.h"
59
#include "prefs_common.h"
60
#include "prefs_account.h"
61
#include "prefs_filter.h"
62
#include "prefs_folder_item.h"
63
#include "account.h"
64
#include "folder.h"
65
#include "inc.h"
66
67
enum
68
{
69
        COL_FOLDER_NAME,
70
        COL_NEW,
71
        COL_UNREAD,
72
        COL_TOTAL,
73
        COL_FOLDER_ITEM,
74
        COL_PIXBUF,
75
        COL_PIXBUF_OPEN,
76
        COL_FOREGROUND,
77
        COL_BOLD,
78
        N_COLS
79
};
80
81
#define COL_FOLDER_WIDTH        150
82
#define COL_NUM_WIDTH                32
83
84
#define STATUSBAR_PUSH(mainwin, str) \
85
{ \
86
        gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
87
                           mainwin->folderview_cid, str); \
88
        gtkut_widget_draw_now(mainwin->statusbar); \
89
}
90
91
#define STATUSBAR_POP(mainwin) \
92
{ \
93
        gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
94
                          mainwin->folderview_cid); \
95
}
96
97
static GList *folderview_list = NULL;
98
99
static GdkPixbuf *inbox_pixbuf;
100
static GdkPixbuf *outbox_pixbuf;
101
static GdkPixbuf *folder_pixbuf;
102
static GdkPixbuf *folderopen_pixbuf;
103
static GdkPixbuf *foldernoselect_pixbuf;
104
static GdkPixbuf *trash_pixbuf;
105
106
static void folderview_select_row        (FolderView        *folderview,
107
                                         GtkTreeIter        *iter);
108
static void folderview_select_row_ref        (FolderView        *folderview,
109
                                         GtkTreeRowReference *row);
110
111
static void folderview_set_folders        (FolderView        *folderview);
112
static void folderview_append_folder        (FolderView        *folderview,
113
                                         Folder                *folder);
114
115
static void folderview_update_row        (FolderView        *folderview,
116
                                         GtkTreeIter        *iter);
117
118
static gint folderview_folder_name_compare        (GtkTreeModel        *model,
119
                                                 GtkTreeIter        *a,
120
                                                 GtkTreeIter        *b,
121
                                                 gpointer         data);
122
123
/* callback functions */
124
static gboolean folderview_button_pressed        (GtkWidget        *treeview,
125
                                                 GdkEventButton        *event,
126
                                                 FolderView        *folderview);
127
static gboolean folderview_button_released        (GtkWidget        *treeview,
128
                                                 GdkEventButton        *event,
129
                                                 FolderView        *folderview);
130
131
static gboolean folderview_key_pressed        (GtkWidget        *widget,
132
                                         GdkEventKey        *event,
133
                                         FolderView        *folderview);
134
135
static void folderview_selection_changed(GtkTreeSelection        *selection,
136
                                         FolderView                *folderview);
137
138
static void folderview_row_expanded        (GtkTreeView                *treeview,
139
                                         GtkTreeIter                *iter,
140
                                         GtkTreePath                *path,
141
                                         FolderView                *folderview);
142
static void folderview_row_collapsed        (GtkTreeView                *treeview,
143
                                         GtkTreeIter                *iter,
144
                                         GtkTreePath                *path,
145
                                         FolderView                *folderview);
146
147
static void folderview_popup_close        (GtkMenuShell        *menu_shell,
148
                                         FolderView        *folderview);
149
150
static void folderview_col_resized        (GtkWidget        *widget,
151
                                         GtkAllocation        *allocation,
152
                                         FolderView        *folderview);
153
154
static void folderview_download_cb        (FolderView        *folderview,
155
                                         guint                 action,
156
                                         GtkWidget        *widget);
157
158
static void folderview_update_tree_cb        (FolderView        *folderview,
159
                                         guint                 action,
160
                                         GtkWidget        *widget);
161
162
static void folderview_new_folder_cb        (FolderView        *folderview,
163
                                         guint                 action,
164
                                         GtkWidget        *widget);
165
static void folderview_rename_folder_cb        (FolderView        *folderview,
166
                                         guint                 action,
167
                                         GtkWidget        *widget);
168
static void folderview_delete_folder_cb        (FolderView        *folderview,
169
                                         guint                 action,
170
                                         GtkWidget        *widget);
171
static void folderview_empty_trash_cb        (FolderView        *folderview,
172
                                         guint                 action,
173
                                         GtkWidget        *widget);
174
static void folderview_remove_mailbox_cb(FolderView        *folderview,
175
                                         guint                 action,
176
                                         GtkWidget        *widget);
177
178
static void folderview_rm_imap_server_cb (FolderView        *folderview,
179
                                          guint                 action,
180
                                          GtkWidget        *widget);
181
182
static void folderview_new_news_group_cb(FolderView        *folderview,
183
                                         guint                 action,
184
                                         GtkWidget        *widget);
185
static void folderview_rm_news_group_cb        (FolderView        *folderview,
186
                                         guint                 action,
187
                                         GtkWidget        *widget);
188
static void folderview_rm_news_server_cb(FolderView        *folderview,
189
                                         guint                 action,
190
                                         GtkWidget        *widget);
191
192
static void folderview_search_cb        (FolderView        *folderview,
193
                                         guint                 action,
194
                                         GtkWidget        *widget);
195
196
static void folderview_property_cb        (FolderView        *folderview,
197
                                         guint                 action,
198
                                         GtkWidget        *widget);
199
200
static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
201
                                          GdkDragContext *context,
202
                                          gint            x,
203
                                          gint            y,
204
                                          guint           time,
205
                                          FolderView     *folderview);
206
static void folderview_drag_leave_cb     (GtkWidget        *widget,
207
                                          GdkDragContext   *context,
208
                                          guint             time,
209
                                          FolderView       *folderview);
210
static void folderview_drag_received_cb  (GtkWidget        *widget,
211
                                          GdkDragContext   *context,
212
                                          gint              x,
213
                                          gint              y,
214
                                          GtkSelectionData *data,
215
                                          guint             info,
216
                                          guint             time,
217
                                          FolderView       *folderview);
218
219
GtkTargetEntry folderview_drag_types[] =
220
{
221
        {"text/plain", GTK_TARGET_SAME_APP, 0}
222
};
223
224
static GtkItemFactoryEntry folderview_mail_popup_entries[] =
225
{
226
        {N_("/Create _new folder..."),        NULL, folderview_new_folder_cb,    0, NULL},
227
        {N_("/_Rename folder..."),        NULL, folderview_rename_folder_cb, 0, NULL},
228
        {N_("/_Delete folder"),                NULL, folderview_delete_folder_cb, 0, NULL},
229
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
230
        {N_("/Empty _trash"),                NULL, folderview_empty_trash_cb, 0, NULL},
231
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
232
        {N_("/_Check for new messages"),
233
                                        NULL, folderview_update_tree_cb, 0, NULL},
234
        {N_("/R_ebuild folder tree"),        NULL, folderview_update_tree_cb, 1, NULL},
235
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
236
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
237
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
238
};
239
240
static GtkItemFactoryEntry folderview_imap_popup_entries[] =
241
{
242
        {N_("/Create _new folder..."),        NULL, folderview_new_folder_cb,    0, NULL},
243
        {N_("/_Rename folder..."),        NULL, folderview_rename_folder_cb, 0, NULL},
244
        {N_("/_Delete folder"),                NULL, folderview_delete_folder_cb, 0, NULL},
245
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
246
        {N_("/Empty _trash"),                NULL, folderview_empty_trash_cb, 0, NULL},
247
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
248
        {N_("/Down_load"),                NULL, folderview_download_cb, 0, NULL},
249
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
250
        {N_("/_Check for new messages"),
251
                                        NULL, folderview_update_tree_cb, 0, NULL},
252
        {N_("/R_ebuild folder tree"),        NULL, folderview_update_tree_cb, 1, NULL},
253
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
254
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
255
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
256
};
257
258
static GtkItemFactoryEntry folderview_news_popup_entries[] =
259
{
260
        {N_("/Su_bscribe to newsgroup..."),
261
                                        NULL, folderview_new_news_group_cb, 0, NULL},
262
        {N_("/_Remove newsgroup"),        NULL, folderview_rm_news_group_cb, 0, NULL},
263
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
264
        {N_("/Down_load"),                NULL, folderview_download_cb, 0, NULL},
265
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
266
        {N_("/_Check for new messages"),
267
                                        NULL, folderview_update_tree_cb, 0, NULL},
268
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
269
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
270
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
271
};
272
273
274
FolderView *folderview_create(void)
275
{
276
        FolderView *folderview;
277
        GtkWidget *scrolledwin;
278
        GtkWidget *treeview;
279
        GtkTreeStore *store;
280
        GtkTreeSelection *selection;
281
        GtkTreeViewColumn *column;
282
        GtkCellRenderer *renderer;
283
        GtkWidget *mail_popup;
284
        GtkWidget *news_popup;
285
        GtkWidget *imap_popup;
286
        GtkItemFactory *mail_factory;
287
        GtkItemFactory *news_factory;
288
        GtkItemFactory *imap_factory;
289
        gint n_entries;
290
291
        debug_print(_("Creating folder view...\n"));
292
        folderview = g_new0(FolderView, 1);
293
294
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
295
        gtk_scrolled_window_set_policy
296
                (GTK_SCROLLED_WINDOW(scrolledwin),
297
                 GTK_POLICY_AUTOMATIC,
298
                 prefs_common.folderview_vscrollbar_policy);
299
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
300
                                            GTK_SHADOW_IN);
301
        gtk_widget_set_size_request(scrolledwin,
302
                                    prefs_common.folderview_width,
303
                                    prefs_common.folderview_height);
304
305
        store = gtk_tree_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING,
306
                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER,
307
                                   GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF,
308
                                   GDK_TYPE_COLOR, G_TYPE_BOOLEAN);
309
        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),
310
                                        COL_FOLDER_NAME,
311
                                        folderview_folder_name_compare,
312
                                        NULL, NULL);
313
314
        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
315
        g_object_unref(G_OBJECT(store));
316
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
317
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), FALSE);
318
        gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview),
319
                                        COL_FOLDER_NAME);
320
        gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), FALSE);
321
        /* g_object_set(treeview, "fixed-height-mode", TRUE, NULL); */
322
323
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
324
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
325
326
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
327
328
        /* create folder icon + name column */
329
        column = gtk_tree_view_column_new();
330
        gtk_tree_view_column_set_spacing(column, 2);
331
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
332
        gtk_tree_view_column_set_fixed_width
333
                (column, prefs_common.folder_col_folder);
334
        gtk_tree_view_column_set_resizable(column, TRUE);
335
336
        renderer = gtk_cell_renderer_pixbuf_new();
337
        g_object_set(renderer, "ypad", 0, NULL);
338
        gtk_tree_view_column_pack_start(column, renderer, FALSE);
339
        gtk_tree_view_column_set_title(column, _("Folder"));
340
        gtk_tree_view_column_set_attributes
341
                (column, renderer,
342
                 "pixbuf", COL_PIXBUF,
343
                 "pixbuf-expander-open", COL_PIXBUF_OPEN,
344
                 "pixbuf-expander-closed", COL_PIXBUF,
345
                 NULL);
346
347
        renderer = gtk_cell_renderer_text_new();
348
#if GTK_CHECK_VERSION(2, 6, 0)
349
        g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ypad", 0,
350
                     NULL);
351
#else
352
        g_object_set(renderer, "ypad", 0, NULL);
353
#endif
354
        gtk_tree_view_column_pack_start(column, renderer, TRUE);
355
        gtk_tree_view_column_set_attributes(column, renderer,
356
                                            "text", COL_FOLDER_NAME,
357
                                            "foreground-gdk", COL_FOREGROUND,
358
                                            "weight-set", COL_BOLD,
359
                                            NULL);
360
        g_object_set(G_OBJECT(renderer), "weight", PANGO_WEIGHT_BOLD, NULL);
361
362
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
363
        gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
364
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
365
                         G_CALLBACK(folderview_col_resized), folderview);
366
367
        renderer = gtk_cell_renderer_text_new();
368
        g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
369
        column = gtk_tree_view_column_new_with_attributes
370
                (_("New"), renderer, "text", COL_NEW, NULL);
371
        gtk_tree_view_column_set_alignment(column, 1.0);
372
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
373
        gtk_tree_view_column_set_fixed_width
374
                (column, prefs_common.folder_col_new);
375
        gtk_tree_view_column_set_min_width(column, 8);
376
        gtk_tree_view_column_set_resizable(column, TRUE);
377
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
378
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
379
                         G_CALLBACK(folderview_col_resized), folderview);
380
381
        renderer = gtk_cell_renderer_text_new();
382
        g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
383
        column = gtk_tree_view_column_new_with_attributes
384
                (_("Unread"), renderer, "text", COL_UNREAD, NULL);
385
        gtk_tree_view_column_set_alignment(column, 1.0);
386
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
387
        gtk_tree_view_column_set_fixed_width
388
                (column, prefs_common.folder_col_unread);
389
        gtk_tree_view_column_set_min_width(column, 8);
390
        gtk_tree_view_column_set_resizable(column, TRUE);
391
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
392
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
393
                         G_CALLBACK(folderview_col_resized), folderview);
394
395
        renderer = gtk_cell_renderer_text_new();
396
        g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
397
        column = gtk_tree_view_column_new_with_attributes
398
                (_("#"), renderer, "text", COL_TOTAL, NULL);
399
        gtk_tree_view_column_set_alignment(column, 1.0);
400
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
401
        gtk_tree_view_column_set_fixed_width
402
                (column, prefs_common.folder_col_total);
403
        gtk_tree_view_column_set_min_width(column, 8);
404
        gtk_tree_view_column_set_resizable(column, TRUE);
405
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
406
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
407
                         G_CALLBACK(folderview_col_resized), folderview);
408
409
        gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
410
                                             COL_FOLDER_NAME,
411
                                             GTK_SORT_ASCENDING);
412
413
        /* popup menu */
414
        n_entries = sizeof(folderview_mail_popup_entries) /
415
                sizeof(folderview_mail_popup_entries[0]);
416
        mail_popup = menu_create_items(folderview_mail_popup_entries,
417
                                       n_entries,
418
                                       "<MailFolder>", &mail_factory,
419
                                       folderview);
420
        n_entries = sizeof(folderview_imap_popup_entries) /
421
                sizeof(folderview_imap_popup_entries[0]);
422
        imap_popup = menu_create_items(folderview_imap_popup_entries,
423
                                       n_entries,
424
                                       "<IMAPFolder>", &imap_factory,
425
                                       folderview);
426
        n_entries = sizeof(folderview_news_popup_entries) /
427
                sizeof(folderview_news_popup_entries[0]);
428
        news_popup = menu_create_items(folderview_news_popup_entries,
429
                                       n_entries,
430
                                       "<NewsFolder>", &news_factory,
431
                                       folderview);
432
433
        g_signal_connect(G_OBJECT(treeview), "button_press_event",
434
                         G_CALLBACK(folderview_button_pressed), folderview);
435
        g_signal_connect(G_OBJECT(treeview), "button_release_event",
436
                         G_CALLBACK(folderview_button_released), folderview);
437
        g_signal_connect(G_OBJECT(treeview), "key_press_event",
438
                         G_CALLBACK(folderview_key_pressed), folderview);
439
440
        g_signal_connect(G_OBJECT(selection), "changed",
441
                         G_CALLBACK(folderview_selection_changed), folderview);
442
443
        g_signal_connect_after(G_OBJECT(treeview), "row-expanded",
444
                               G_CALLBACK(folderview_row_expanded),
445
                               folderview);
446
        g_signal_connect_after(G_OBJECT(treeview), "row-collapsed",
447
                               G_CALLBACK(folderview_row_collapsed),
448
                               folderview);
449
450
        g_signal_connect(G_OBJECT(mail_popup), "selection_done",
451
                         G_CALLBACK(folderview_popup_close), folderview);
452
        g_signal_connect(G_OBJECT(imap_popup), "selection_done",
453
                         G_CALLBACK(folderview_popup_close), folderview);
454
        g_signal_connect(G_OBJECT(news_popup), "selection_done",
455
                         G_CALLBACK(folderview_popup_close), folderview);
456
457
        /* drop callback */
458
        gtk_drag_dest_set(treeview, GTK_DEST_DEFAULT_ALL,
459
                          folderview_drag_types, 1,
460
                          GDK_ACTION_MOVE | GDK_ACTION_COPY);
461
        g_signal_connect(G_OBJECT(treeview), "drag-motion",
462
                         G_CALLBACK(folderview_drag_motion_cb),
463
                         folderview);
464
        g_signal_connect(G_OBJECT(treeview), "drag-leave",
465
                         G_CALLBACK(folderview_drag_leave_cb),
466
                         folderview);
467
        g_signal_connect(G_OBJECT(treeview), "drag-data-received",
468
                         G_CALLBACK(folderview_drag_received_cb),
469
                         folderview);
470
471
        folderview->scrolledwin  = scrolledwin;
472
        folderview->treeview     = treeview;
473
        folderview->store        = store;
474
        folderview->selection    = selection;
475
        folderview->mail_popup   = mail_popup;
476
        folderview->mail_factory = mail_factory;
477
        folderview->imap_popup   = imap_popup;
478
        folderview->imap_factory = imap_factory;
479
        folderview->news_popup   = news_popup;
480
        folderview->news_factory = news_factory;
481
482
        gtk_widget_show_all(scrolledwin);
483
484
        folderview_list = g_list_append(folderview_list, folderview);
485
486
        return folderview;
487
}
488
489
void folderview_init(FolderView *folderview)
490
{
491
        GtkWidget *treeview = folderview->treeview;
492
493
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_INBOX, &inbox_pixbuf);
494
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_OUTBOX, &outbox_pixbuf);
495
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DIR_CLOSE, &folder_pixbuf);
496
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DIR_OPEN, &folderopen_pixbuf);
497
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DIR_NOSELECT,
498
                         &foldernoselect_pixbuf);
499
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_TRASH, &trash_pixbuf);
500
}
501
502
FolderView *folderview_get(void)
503
{
504
        return (FolderView *)folderview_list->data;
505
}
506
507
void folderview_set(FolderView *folderview)
508
{
509
        MainWindow *mainwin = folderview->mainwin;
510
        GtkTreeIter iter;
511
512
        debug_print(_("Setting folder info...\n"));
513
        STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
514
515
        main_window_cursor_wait(mainwin);
516
517
        folderview_unselect(folderview);
518
519
        gtk_tree_store_clear(folderview->store);
520
521
        folderview_set_folders(folderview);
522
523
        if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(folderview->store),
524
                                          &iter))
525
                folderview_select_row(folderview, &iter);
526
527
        main_window_cursor_normal(mainwin);
528
        STATUSBAR_POP(mainwin);
529
}
530
531
void folderview_set_all(void)
532
{
533
        GList *list;
534
535
        for (list = folderview_list; list != NULL; list = list->next)
536
                folderview_set((FolderView *)list->data);
537
}
538
539
void folderview_select(FolderView *folderview, FolderItem *item)
540
{
541
        GtkTreeIter iter;
542
543
        if (!item) return;
544
545
        if (gtkut_tree_model_find_by_column_data
546
                (GTK_TREE_MODEL(folderview->store), &iter, NULL,
547
                 COL_FOLDER_ITEM, item))
548
                folderview_select_row(folderview, &iter);
549
}
550
551
static void folderview_select_row(FolderView *folderview, GtkTreeIter *iter)
552
{
553
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
554
        GtkTreePath *path;
555
556
        g_return_if_fail(iter != NULL);
557
558
        path = gtk_tree_model_get_path(model, iter);
559
560
        gtkut_tree_view_expand_parent_all(GTK_TREE_VIEW(folderview->treeview),
561
                                          iter);
562
563
        folderview->open_folder = TRUE;
564
        gtk_tree_view_set_cursor(GTK_TREE_VIEW(folderview->treeview), path,
565
                                 NULL, FALSE);
566
        if (folderview->summaryview->folder_item &&
567
            folderview->summaryview->folder_item->total > 0)
568
                gtk_widget_grab_focus(folderview->summaryview->treeview);
569
        else
570
                gtk_widget_grab_focus(folderview->treeview);
571
572
        gtk_tree_path_free(path);
573
}
574
575
static void folderview_select_row_ref(FolderView *folderview,
576
                                      GtkTreeRowReference *row)
577
{
578
        GtkTreePath *path;
579
        GtkTreeIter iter;
580
581
        if (!row) return;
582
583
        path = gtk_tree_row_reference_get_path(row);
584
        if (!path)
585
                return;
586
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
587
        gtk_tree_path_free(path);
588
589
        folderview_select_row(folderview, &iter);
590
}
591
592
void folderview_unselect(FolderView *folderview)
593
{
594
        if (folderview->selected) {
595
                gtk_tree_row_reference_free(folderview->selected);
596
                folderview->selected = NULL;
597
        }
598
        if (folderview->opened) {
599
                gtk_tree_row_reference_free(folderview->opened);
600
                folderview->opened = NULL;
601
        }
602
}
603
604
static gboolean folderview_find_next_unread(GtkTreeModel *model,
605
                                            GtkTreeIter *next,
606
                                            GtkTreeIter *iter)
607
{
608
        FolderItem *item;
609
        GtkTreeIter iter_;
610
        gboolean valid;
611
612
        if (iter) {
613
                iter_ = *iter;
614
                valid = gtkut_tree_model_next(model, &iter_);
615
        } else
616
                valid = gtk_tree_model_get_iter_first(model, &iter_);
617
618
        while (valid) {
619
                item = NULL;
620
                gtk_tree_model_get(model, &iter_, COL_FOLDER_ITEM, &item, -1);
621
                if (item && item->unread > 0 && item->stype != F_TRASH) {
622
                        if (next)
623
                                *next = iter_;
624
                        return TRUE;
625
                }
626
627
                valid = gtkut_tree_model_next(model, &iter_);
628
        }
629
630
        return FALSE;
631
}
632
633
void folderview_select_next_unread(FolderView *folderview)
634
{
635
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
636
        GtkTreeIter iter, next;
637
638
        if (folderview->opened) {
639
                GtkTreePath *path;
640
641
                path = gtk_tree_row_reference_get_path(folderview->opened);
642
                if (!path)
643
                        return;
644
                gtk_tree_model_get_iter(model, &iter, path);
645
                gtk_tree_path_free(path);
646
        } else {
647
                if (!gtk_tree_model_get_iter_first(model, &iter))
648
                        return;
649
        }
650
        if (folderview_find_next_unread(model, &next, &iter)) {
651
                folderview_select_row(folderview, &next);
652
                return;
653
        }
654
655
        if (!folderview->opened)
656
                return;
657
658
        /* search again from the first row */
659
        if (folderview_find_next_unread(model, &next, NULL))
660
                folderview_select_row(folderview, &next);
661
}
662
663
FolderItem *folderview_get_selected_item(FolderView *folderview)
664
{
665
        GtkTreePath *path;
666
        GtkTreeIter iter;
667
        FolderItem *item = NULL;
668
669
        if (!folderview->selected)
670
                return NULL;
671
672
        path = gtk_tree_row_reference_get_path(folderview->selected);
673
        if (!path)
674
                return NULL;
675
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
676
        gtk_tree_path_free(path);
677
        gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), &iter,
678
                           COL_FOLDER_ITEM, &item, -1);
679
680
        return item;
681
}
682
683
void folderview_set_opened_item(FolderView *folderview, FolderItem *item)
684
{
685
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
686
        GtkTreeIter iter;
687
        GtkTreePath *path;
688
689
        gtk_tree_row_reference_free(folderview->opened);
690
        folderview->opened = NULL;
691
692
        if (!item)
693
                return;
694
695
        if (gtkut_tree_model_find_by_column_data
696
                 (model, &iter, NULL, COL_FOLDER_ITEM, item)) {
697
                path = gtk_tree_model_get_path(model, &iter);
698
                folderview->opened = gtk_tree_row_reference_new(model, path);
699
                gtk_tree_path_free(path);
700
        }
701
}
702
703
void folderview_update_opened_msg_num(FolderView *folderview)
704
{
705
        GtkTreePath *path;
706
        GtkTreeIter iter;
707
708
        if (!folderview->opened)
709
                return;
710
711
        path = gtk_tree_row_reference_get_path(folderview->opened);
712
        if (!path)
713
                return;
714
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
715
        gtk_tree_path_free(path);
716
717
        folderview_update_row(folderview, &iter);
718
}
719
720
gboolean folderview_append_item(FolderView *folderview, GtkTreeIter *iter,
721
                                FolderItem *item)
722
{
723
        FolderItem *parent_item;
724
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
725
        GtkTreeIter iter_, child;
726
        GtkTreeIter *iter_p = &iter_;
727
728
        g_return_val_if_fail(item != NULL, FALSE);
729
        g_return_val_if_fail(item->folder != NULL, FALSE);
730
731
        parent_item = item->parent;
732
733
        if (!parent_item)
734
                iter_p = NULL;
735
        else if (!gtkut_tree_model_find_by_column_data
736
                (model, iter_p, NULL, COL_FOLDER_ITEM, parent_item))
737
                return FALSE;
738
739
        if (!gtkut_tree_model_find_by_column_data
740
                (model, &child, iter_p, COL_FOLDER_ITEM, item)) {
741
                gtk_tree_store_append(folderview->store, &child, iter_p);
742
                gtk_tree_store_set(folderview->store, &child,
743
                                   COL_FOLDER_NAME, item->name,
744
                                   COL_FOLDER_ITEM, item,
745
                                   -1);
746
                folderview_update_row(folderview, &child);
747
                if (iter)
748
                        *iter = child;
749
                return TRUE;
750
        }
751
752
        return FALSE;
753
}
754
755
static void folderview_set_folders(FolderView *folderview)
756
{
757
        GList *list;
758
759
        list = folder_get_list();
760
761
        for (; list != NULL; list = list->next)
762
                folderview_append_folder(folderview, FOLDER(list->data));
763
}
764
765
static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
766
                                      gpointer data)
767
{
768
        GList *list;
769
        gchar *rootpath;
770
771
        if (FOLDER_IS_LOCAL(folder))
772
                rootpath = LOCAL_FOLDER(folder)->rootpath;
773
        else if (FOLDER_TYPE(folder) == F_IMAP && folder->account &&
774
                 folder->account->recv_server)
775
                rootpath = folder->account->recv_server;
776
        else if (FOLDER_TYPE(folder) == F_NEWS && folder->account &&
777
                 folder->account->nntp_server)
778
                rootpath = folder->account->nntp_server;
779
        else
780
                return;
781
782
        for (list = folderview_list; list != NULL; list = list->next) {
783
                FolderView *folderview = (FolderView *)list->data;
784
                MainWindow *mainwin = folderview->mainwin;
785
                gchar *str;
786
787
                if (item->path)
788
                        str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
789
                                              rootpath, G_DIR_SEPARATOR,
790
                                              item->path);
791
                else
792
                        str = g_strdup_printf(_("Scanning folder %s ..."),
793
                                              rootpath);
794
795
                STATUSBAR_PUSH(mainwin, str);
796
                STATUSBAR_POP(mainwin);
797
                g_free(str);
798
        }
799
}
800
801
static GtkWidget *label_window_create(const gchar *str)
802
{
803
        GtkWidget *window;
804
        GtkWidget *label;
805
806
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
807
        gtk_widget_set_size_request(window, 380, 60);
808
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
809
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
810
        gtk_window_set_title(GTK_WINDOW(window), str);
811
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
812
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
813
        manage_window_set_transient(GTK_WINDOW(window));
814
815
        label = gtk_label_new(str);
816
        gtk_container_add(GTK_CONTAINER(window), label);
817
        gtk_widget_show(label);
818
819
        gtk_widget_show_now(window);
820
821
        return window;
822
}
823
824
static void folderview_rescan_tree(FolderView *folderview, Folder *folder)
825
{
826
        GtkWidget *window;
827
        AlertValue avalue;
828
829
        g_return_if_fail(folder != NULL);
830
831
        if (!folder->klass->scan_tree) return;
832
833
        avalue = alertpanel
834
                (_("Rebuild folder tree"),
835
                 _("The folder tree will be rebuilt. Continue?"),
836
                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
837
        if (avalue != G_ALERTDEFAULT) return;
838
839
        if (!FOLDER_IS_LOCAL(folder) &&
840
            !main_window_toggle_online_if_offline(folderview->mainwin))
841
                return;
842
843
        inc_lock();
844
        window = label_window_create(_("Rebuilding folder tree..."));
845
846
        summary_show(folderview->summaryview, NULL, FALSE);
847
        GTK_EVENTS_FLUSH();
848
849
        folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
850
        if (folder->klass->scan_tree(folder) < 0)
851
                alertpanel_error(_("Rebuilding of the folder tree failed."));
852
        folder_set_ui_func(folder, NULL, NULL);
853
854
        folder_write_list();
855
        folderview_set_all();
856
        statusbar_pop_all();
857
858
        gtk_widget_destroy(window);
859
        inc_unlock();
860
}
861
862
void folderview_check_new(Folder *folder)
863
{
864
        FolderItem *item;
865
        FolderView *folderview;
866
        GtkTreeModel *model;
867
        GtkTreeIter iter;
868
        gboolean valid;
869
870
        folderview = (FolderView *)folderview_list->data;
871
        model = GTK_TREE_MODEL(folderview->store);
872
873
        if (folder && !FOLDER_IS_LOCAL(folder)) {
874
                if (!main_window_toggle_online_if_offline
875
                        (folderview->mainwin))
876
                        return;
877
        }
878
879
        inc_lock();
880
        main_window_lock(folderview->mainwin);
881
        gtk_widget_set_sensitive(folderview->treeview, FALSE);
882
        GTK_EVENTS_FLUSH();
883
884
        for (valid = gtk_tree_model_get_iter_first(model, &iter);
885
             valid; valid = gtkut_tree_model_next(model, &iter)) {
886
                item = NULL;
887
                gtk_tree_model_get(model, &iter,
888
                                   COL_FOLDER_ITEM, &item, -1);
889
                if (!item || !item->path || !item->folder) continue;
890
                if (item->no_select) continue;
891
                if (folder && folder != item->folder) continue;
892
                if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
893
894
                folderview_scan_tree_func(item->folder, item, NULL);
895
                if (folder_item_scan(item) < 0) {
896
                        if (folder && !FOLDER_IS_LOCAL(folder))
897
                                break;
898
                }
899
                folderview_update_row(folderview, &iter);
900
        }
901
902
        gtk_widget_set_sensitive(folderview->treeview, TRUE);
903
        main_window_unlock(folderview->mainwin);
904
        inc_unlock();
905
        statusbar_pop_all();
906
907
        folder_write_list();
908
}
909
910
void folderview_check_new_all(void)
911
{
912
        GList *list;
913
        GtkWidget *window;
914
        FolderView *folderview;
915
916
        folderview = (FolderView *)folderview_list->data;
917
918
        inc_lock();
919
        main_window_lock(folderview->mainwin);
920
        window = label_window_create
921
                (_("Checking for new messages in all folders..."));
922
923
        list = folder_get_list();
924
        for (; list != NULL; list = list->next) {
925
                Folder *folder = list->data;
926
927
                folderview_check_new(folder);
928
        }
929
930
        gtk_widget_destroy(window);
931
        main_window_unlock(folderview->mainwin);
932
        inc_unlock();
933
}
934
935
static gboolean folderview_search_new_recursive(GtkTreeModel *model,
936
                                                GtkTreeIter *iter)
937
{
938
        FolderItem *item = NULL;
939
        GtkTreeIter iter_;
940
        gboolean valid;
941
942
        if (iter) {
943
                gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
944
                if (item) {
945
                        if (item->new > 0 ||
946
                            (item->stype == F_QUEUE && item->total > 0))
947
                                return TRUE;
948
                }
949
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
950
        } else
951
                valid = gtk_tree_model_get_iter_first(model, &iter_);
952
953
        while (valid) {
954
                if (folderview_search_new_recursive(model, &iter_) == TRUE)
955
                        return TRUE;
956
                valid = gtk_tree_model_iter_next(model, &iter_);
957
        }
958
959
        return FALSE;
960
}
961
962
static gboolean folderview_have_new_children(FolderView *folderview,
963
                                             GtkTreeIter *iter)
964
{
965
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
966
        GtkTreeIter iter_;
967
        gboolean valid;
968
969
        if (iter)
970
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
971
        else
972
                valid = gtk_tree_model_get_iter_first(model, &iter_);
973
974
        while (valid) {
975
                if (folderview_search_new_recursive(model, &iter_) == TRUE)
976
                        return TRUE;
977
                valid = gtk_tree_model_iter_next(model, &iter_);
978
        }
979
980
        return FALSE;
981
}
982
983
static gboolean folderview_search_unread_recursive(GtkTreeModel *model,
984
                                                   GtkTreeIter *iter)
985
{
986
        FolderItem *item = NULL;
987
        GtkTreeIter iter_;
988
        gboolean valid;
989
990
        if (iter) {
991
                gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
992
                if (item) {
993
                        if (item->unread > 0 ||
994
                            (item->stype == F_QUEUE && item->total > 0))
995
                                return TRUE;
996
                }
997
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
998
        } else
999
                valid = gtk_tree_model_get_iter_first(model, &iter_);
1000
1001
        while (valid) {
1002
                if (folderview_search_unread_recursive(model, &iter_) == TRUE)
1003
                        return TRUE;
1004
                valid = gtk_tree_model_iter_next(model, &iter_);
1005
        }
1006
1007
        return FALSE;
1008
}
1009
1010
static gboolean folderview_have_unread_children(FolderView *folderview,
1011
                                                GtkTreeIter *iter)
1012
{
1013
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1014
        GtkTreeIter iter_;
1015
        gboolean valid;
1016
1017
        if (iter)
1018
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
1019
        else
1020
                valid = gtk_tree_model_get_iter_first(model, &iter_);
1021
1022
        while (valid) {
1023
                if (folderview_search_unread_recursive(model, &iter_) == TRUE)
1024
                        return TRUE;
1025
                valid = gtk_tree_model_iter_next(model, &iter_);
1026
        }
1027
1028
        return FALSE;
1029
}
1030
1031
static void folderview_update_row(FolderView *folderview, GtkTreeIter *iter)
1032
{
1033
        GtkTreeStore *store = folderview->store;
1034
        GtkTreeModel *model = GTK_TREE_MODEL(store);
1035
        GtkTreePath *path;
1036
        GtkTreeIter parent;
1037
        FolderItem *item = NULL;
1038
        GdkPixbuf *pixbuf, *open_pixbuf;
1039
        gchar *name, *str;
1040
        gchar new_s[11], unread_s[11], total_s[11];
1041
        gboolean add_unread_mark;
1042
        gboolean use_bold, use_color;
1043
        GdkColor *foreground = NULL;
1044
1045
        gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
1046
        g_return_if_fail(item != NULL);
1047
1048
        switch (item->stype) {
1049
        case F_INBOX:
1050
                pixbuf = open_pixbuf = inbox_pixbuf;
1051
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1052
                                !strcmp2(item->name, INBOX_DIR) ? _("Inbox") :
1053
                                item->name);
1054
                break;
1055
        case F_OUTBOX:
1056
                pixbuf = open_pixbuf = outbox_pixbuf;
1057
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1058
                                !strcmp2(item->name, OUTBOX_DIR) ? _("Sent") :
1059
                                item->name);
1060
                break;
1061
        case F_QUEUE:
1062
                pixbuf = open_pixbuf = outbox_pixbuf;
1063
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1064
                                !strcmp2(item->name, QUEUE_DIR) ? _("Queue") :
1065
                                item->name);
1066
                break;
1067
        case F_TRASH:
1068
                pixbuf = open_pixbuf = trash_pixbuf;
1069
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1070
                                !strcmp2(item->name, TRASH_DIR) ? _("Trash") :
1071
                                item->name);
1072
                break;
1073
        case F_DRAFT:
1074
                pixbuf = folder_pixbuf;
1075
                open_pixbuf = folderopen_pixbuf;
1076
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1077
                                !strcmp2(item->name, DRAFT_DIR) ? _("Drafts") :
1078
                                item->name);
1079
                break;
1080
        default:
1081
                if (item->no_select) {
1082
                        pixbuf = open_pixbuf = foldernoselect_pixbuf;
1083
                } else {
1084
                        pixbuf = folder_pixbuf;
1085
                        open_pixbuf = folderopen_pixbuf;
1086
                }
1087
1088
                if (!item->parent) {
1089
                        switch (FOLDER_TYPE(item->folder)) {
1090
                        case F_MH:
1091
                                name = " (MH)"; break;
1092
                        case F_IMAP:
1093
                                name = " (IMAP4)"; break;
1094
                        case F_NEWS:
1095
                                name = " (News)"; break;
1096
                        default:
1097
                                name = "";
1098
                        }
1099
                        name = g_strconcat(item->name, name, NULL);
1100
                } else {
1101
                        if (FOLDER_TYPE(item->folder) == F_NEWS &&
1102
                            item->path &&
1103
                            !strcmp2(item->name, item->path))
1104
                                name = get_abbrev_newsgroup_name
1105
                                        (item->path,
1106
                                         prefs_common.ng_abbrev_len);
1107
                        else
1108
                                name = g_strdup(item->name);
1109
                }
1110
        }
1111
1112
        path = gtk_tree_model_get_path(model, iter);
1113
        if (!gtk_tree_view_row_expanded
1114
                (GTK_TREE_VIEW(folderview->treeview), path) &&
1115
            folderview_have_unread_children(folderview, iter))
1116
                add_unread_mark = TRUE;
1117
        else
1118
                add_unread_mark = FALSE;
1119
        gtk_tree_path_free(path);
1120
1121
        if (item->stype == F_QUEUE && item->total > 0 &&
1122
            prefs_common.display_folder_unread) {
1123
                str = g_strdup_printf("%s (%d%s)", name, item->total,
1124
                                      add_unread_mark ? "+" : "");
1125
                g_free(name);
1126
                name = str;
1127
        } else if ((item->unread > 0 || add_unread_mark) &&
1128
                   prefs_common.display_folder_unread) {
1129
                if (item->unread > 0)
1130
                        str = g_strdup_printf("%s (%d%s)", name, item->unread,
1131
                                              add_unread_mark ? "+" : "");
1132
                else
1133
                        str = g_strdup_printf("%s (+)", name);
1134
                g_free(name);
1135
                name = str;
1136
        }
1137
1138
        if (!item->parent) {
1139
                strcpy(new_s, "-");
1140
                strcpy(unread_s, "-");
1141
                strcpy(total_s, "-");
1142
        } else {
1143
                itos_buf(new_s, item->new);
1144
                itos_buf(unread_s, item->unread);
1145
                itos_buf(total_s, item->total);
1146
        }
1147
1148
        if (item->stype == F_OUTBOX || item->stype == F_DRAFT ||
1149
            item->stype == F_TRASH) {
1150
                use_bold = use_color = FALSE;
1151
        } else if (item->stype == F_QUEUE) {
1152
                /* highlight queue folder if there are any messages */
1153
                use_bold = use_color = (item->total > 0);
1154
        } else {
1155
                /* if unread messages exist, print with bold font */
1156
                use_bold = (item->unread > 0) || add_unread_mark;
1157
                /* if new messages exist, print with colored letter */
1158
                use_color =
1159
                        (item->new > 0) ||
1160
                        (add_unread_mark &&
1161
                         folderview_have_new_children(folderview, iter));
1162
        }
1163
1164
        if (item->no_select)
1165
                foreground = &folderview->color_noselect;
1166
        else if (use_color)
1167
                foreground = &folderview->color_new;
1168
1169
        gtk_tree_store_set(store, iter,
1170
                           COL_FOLDER_NAME, name,
1171
                           COL_NEW, new_s,
1172
                           COL_UNREAD, unread_s,
1173
                           COL_TOTAL, total_s,
1174
                           COL_FOLDER_ITEM, item,
1175
                           COL_PIXBUF, pixbuf,
1176
                           COL_PIXBUF_OPEN, open_pixbuf,
1177
                           COL_FOREGROUND, foreground,
1178
                           COL_BOLD, use_bold,
1179
                           -1);
1180
        g_free(name);
1181
1182
        item->updated = FALSE;
1183
1184
        if (gtkut_tree_view_find_collapsed_parent
1185
                (GTK_TREE_VIEW(folderview->treeview), &parent, iter))
1186
                folderview_update_row(folderview, &parent);
1187
}
1188
1189
void folderview_update_item(FolderItem *item, gboolean update_summary)
1190
{
1191
        FolderView *folderview;
1192
        GtkTreeIter iter;
1193
1194
        g_return_if_fail(item != NULL);
1195
1196
        folderview = folderview_get();
1197
1198
        if (gtkut_tree_model_find_by_column_data
1199
                (GTK_TREE_MODEL(folderview->store), &iter, NULL,
1200
                 COL_FOLDER_ITEM, item)) {
1201
                folderview_update_row(folderview, &iter);
1202
                if (update_summary &&
1203
                    folderview->summaryview->folder_item == item)
1204
                        summary_show(folderview->summaryview, item, FALSE);
1205
        }
1206
}
1207
1208
static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1209
                                                gpointer data)
1210
{
1211
        folderview_update_item((FolderItem *)key, GPOINTER_TO_INT(data));
1212
}
1213
1214
void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1215
{
1216
        g_hash_table_foreach(table, folderview_update_item_foreach_func,
1217
                             GINT_TO_POINTER(update_summary));
1218
}
1219
1220
static gboolean folderview_update_all_updated_func(GNode *node, gpointer data)
1221
{
1222
        FolderItem *item;
1223
1224
        item = FOLDER_ITEM(node->data);
1225
        if (item->updated) {
1226
                debug_print("folderview_update_all_updated(): '%s' is updated\n", item->path);
1227
                folderview_update_item(item, GPOINTER_TO_INT(data));
1228
        }
1229
1230
        return FALSE;
1231
}
1232
1233
void folderview_update_all_updated(gboolean update_summary)
1234
{
1235
        GList *list;
1236
        Folder *folder;
1237
1238
        for (list = folder_get_list(); list != NULL; list = list->next) {
1239
                folder = (Folder *)list->data;
1240
                g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1241
                                folderview_update_all_updated_func,
1242
                                GINT_TO_POINTER(update_summary));
1243
        }
1244
}
1245
1246
static void folderview_insert_item_recursive(FolderView *folderview,
1247
                                             FolderItem *item)
1248
{
1249
        GNode *node;
1250
        GtkTreeIter iter;
1251
        gboolean valid;
1252
1253
        g_return_if_fail(item != NULL);
1254
1255
        valid = folderview_append_item(folderview, &iter, item);
1256
        g_return_if_fail(valid == TRUE);
1257
1258
        for (node = item->node->children; node != NULL; node = node->next) {
1259
                FolderItem *child_item = FOLDER_ITEM(node->data);
1260
                folderview_insert_item_recursive(folderview, child_item);
1261
        }
1262
1263
        if (item->node->children && !item->collapsed) {
1264
                GtkTreePath *path;
1265
1266
                path = gtk_tree_model_get_path
1267
                        (GTK_TREE_MODEL(folderview->store), &iter);
1268
                gtk_tree_view_expand_row(GTK_TREE_VIEW(folderview->treeview),
1269
                                         path, FALSE);
1270
                gtk_tree_path_free(path);
1271
        }
1272
}
1273
1274
static void folderview_append_folder(FolderView *folderview, Folder *folder)
1275
{
1276
        g_return_if_fail(folder != NULL);
1277
1278
        folderview_insert_item_recursive
1279
                (folderview, FOLDER_ITEM(folder->node->data));
1280
}
1281
1282
void folderview_new_folder(FolderView *folderview)
1283
{
1284
        FolderItem *item;
1285
1286
        item = folderview_get_selected_item(folderview);
1287
        if (!item)
1288
                return;
1289
1290
        g_return_if_fail(item->folder != NULL);
1291
1292
        switch (FOLDER_TYPE(item->folder)) {
1293
        case F_MH:
1294
        case F_MBOX:
1295
        case F_MAILDIR:
1296
        case F_IMAP:
1297
                folderview_new_folder_cb(folderview, 0, NULL);
1298
                break;
1299
        case F_NEWS:
1300
                folderview_new_news_group_cb(folderview, 0, NULL);
1301
                break;
1302
        default:
1303
                break;
1304
        }
1305
}
1306
1307
void folderview_rename_folder(FolderView *folderview)
1308
{
1309
        FolderItem *item;
1310
1311
        item = folderview_get_selected_item(folderview);
1312
        if (!item)
1313
                return;
1314
1315
        g_return_if_fail(item->folder != NULL);
1316
1317
        if (!item->path) return;
1318
        if (item->stype != F_NORMAL) return;
1319
1320
        switch (FOLDER_TYPE(item->folder)) {
1321
        case F_MH:
1322
        case F_MBOX:
1323
        case F_MAILDIR:
1324
        case F_IMAP:
1325
                folderview_rename_folder_cb(folderview, 0, NULL);
1326
                break;
1327
        case F_NEWS:
1328
        default:
1329
                break;
1330
        }
1331
}
1332
1333
void folderview_delete_folder(FolderView *folderview)
1334
{
1335
        FolderItem *item;
1336
1337
        item = folderview_get_selected_item(folderview);
1338
        if (!item)
1339
                return;
1340
1341
        g_return_if_fail(item->folder != NULL);
1342
1343
        if (!item->path) return;
1344
        if (item->stype != F_NORMAL) return;
1345
1346
        switch (FOLDER_TYPE(item->folder)) {
1347
        case F_MH:
1348
        case F_MBOX:
1349
        case F_MAILDIR:
1350
        case F_IMAP:
1351
                folderview_delete_folder_cb(folderview, 0, NULL);
1352
                break;
1353
        case F_NEWS:
1354
                folderview_rm_news_group_cb(folderview, 0, NULL);
1355
                break;
1356
        default:
1357
                break;
1358
        }
1359
}
1360
1361
void folderview_check_new_selected(FolderView *folderview)
1362
{
1363
        FolderItem *item;
1364
1365
        item = folderview_get_selected_item(folderview);
1366
        if (!item)
1367
                return;
1368
1369
        g_return_if_fail(item->folder != NULL);
1370
        if (item->parent != NULL) return;
1371
1372
        folderview_check_new(item->folder);
1373
}
1374
1375
void folderview_remove_mailbox(FolderView *folderview)
1376
{
1377
        FolderItem *item;
1378
1379
        item = folderview_get_selected_item(folderview);
1380
        if (!item)
1381
                return;
1382
1383
        g_return_if_fail(item->folder != NULL);
1384
        if (item->parent != NULL) return;
1385
1386
        switch (FOLDER_TYPE(item->folder)) {
1387
        case F_MH:
1388
        case F_MBOX:
1389
        case F_MAILDIR:
1390
                folderview_remove_mailbox_cb(folderview, 0, NULL);
1391
                break;
1392
        case F_IMAP:
1393
                folderview_rm_imap_server_cb(folderview, 0, NULL);
1394
                break;
1395
        case F_NEWS:
1396
                folderview_rm_news_server_cb(folderview, 0, NULL);
1397
                break;
1398
        default:
1399
                break;
1400
        }
1401
}
1402
1403
void folderview_rebuild_tree(FolderView *folderview)
1404
{
1405
        FolderItem *item;
1406
1407
        item = folderview_get_selected_item(folderview);
1408
        if (!item)
1409
                return;
1410
1411
        g_return_if_fail(item->folder != NULL);
1412
        if (item->parent != NULL) return;
1413
1414
        folderview_rescan_tree(folderview, item->folder);
1415
}
1416
1417
static gboolean folderview_menu_popup(FolderView *folderview,
1418
                                      GdkEventButton *event)
1419
{
1420
        FolderItem *item = NULL;
1421
        Folder *folder;
1422
        GtkWidget *popup;
1423
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1424
        GtkTreeIter iter;
1425
        gboolean new_folder      = FALSE;
1426
        gboolean rename_folder   = FALSE;
1427
        gboolean delete_folder   = FALSE;
1428
        gboolean empty_trash     = FALSE;
1429
        gboolean download_msg    = FALSE;
1430
        gboolean update_tree     = FALSE;
1431
        gboolean rescan_tree     = FALSE;
1432
        gboolean remove_tree     = FALSE;
1433
        gboolean search_folder   = FALSE;
1434
        gboolean folder_property = FALSE;
1435
1436
        if (!event) return FALSE;
1437
1438
        if (event->button != 3)
1439
                return FALSE;
1440
1441
        if (!gtk_tree_selection_get_selected
1442
                (folderview->selection, NULL, &iter))
1443
                return FALSE;
1444
1445
        gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
1446
        g_return_val_if_fail(item != NULL, FALSE);
1447
        g_return_val_if_fail(item->folder != NULL, FALSE);
1448
        folder = item->folder;
1449
1450
        if (folderview->mainwin->lock_count == 0) {
1451
                new_folder = TRUE;
1452
                if (item->parent == NULL) {
1453
                        update_tree = remove_tree = TRUE;
1454
                        if (folder->account)
1455
                                folder_property = TRUE;
1456
                } else {
1457
                        folder_property = TRUE;
1458
                        if (gtkut_tree_row_reference_equal(folderview->selected,
1459
                                                           folderview->opened))
1460
                                search_folder = TRUE;
1461
                }
1462
                if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP) {
1463
                        if (item->parent == NULL)
1464
                                update_tree = rescan_tree = TRUE;
1465
                        else if (item->stype == F_NORMAL)
1466
                                rename_folder = delete_folder = TRUE;
1467
                        else if (item->stype == F_TRASH)
1468
                                empty_trash = TRUE;
1469
                } else if (FOLDER_TYPE(folder) == F_NEWS) {
1470
                        if (item->parent != NULL)
1471
                                delete_folder = TRUE;
1472
                }
1473
                if (FOLDER_TYPE(folder) == F_IMAP ||
1474
                    FOLDER_TYPE(folder) == F_NEWS) {
1475
                        if (item->parent != NULL && item->no_select == FALSE)
1476
                                download_msg = TRUE;
1477
                }
1478
        }
1479
1480
#define SET_SENS(factory, name, sens) \
1481
        menu_set_sensitive(folderview->factory, name, sens)
1482
1483
        if (FOLDER_IS_LOCAL(folder)) {
1484
                popup = folderview->mail_popup;
1485
                menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1486
                SET_SENS(mail_factory, "/Create new folder...", new_folder);
1487
                SET_SENS(mail_factory, "/Rename folder...", rename_folder);
1488
                SET_SENS(mail_factory, "/Delete folder", delete_folder);
1489
                SET_SENS(mail_factory, "/Empty trash", empty_trash);
1490
                SET_SENS(mail_factory, "/Check for new messages", update_tree);
1491
                SET_SENS(mail_factory, "/Rebuild folder tree", rescan_tree);
1492
                SET_SENS(mail_factory, "/Search messages...", search_folder);
1493
                SET_SENS(mail_factory, "/Properties...", folder_property);
1494
        } else if (FOLDER_TYPE(folder) == F_IMAP) {
1495
                popup = folderview->imap_popup;
1496
                menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1497
                SET_SENS(imap_factory, "/Create new folder...", new_folder);
1498
                SET_SENS(imap_factory, "/Rename folder...", rename_folder);
1499
                SET_SENS(imap_factory, "/Delete folder", delete_folder);
1500
                SET_SENS(imap_factory, "/Empty trash", empty_trash);
1501
                SET_SENS(imap_factory, "/Download", download_msg);
1502
                SET_SENS(imap_factory, "/Check for new messages", update_tree);
1503
                SET_SENS(imap_factory, "/Rebuild folder tree", rescan_tree);
1504
                SET_SENS(imap_factory, "/Search messages...", search_folder);
1505
                SET_SENS(imap_factory, "/Properties...", folder_property);
1506
        } else if (FOLDER_TYPE(folder) == F_NEWS) {
1507
                popup = folderview->news_popup;
1508
                menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1509
                SET_SENS(news_factory, "/Subscribe to newsgroup...", new_folder);
1510
                SET_SENS(news_factory, "/Remove newsgroup", delete_folder);
1511
                SET_SENS(news_factory, "/Download", download_msg);
1512
                SET_SENS(news_factory, "/Check for new messages", update_tree);
1513
                SET_SENS(news_factory, "/Search messages...", search_folder);
1514
                SET_SENS(news_factory, "/Properties...", folder_property);
1515
        } else
1516
                return FALSE;
1517
1518
#undef SET_SENS
1519
1520
        gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1521
                       event->button, event->time);
1522
1523
        return FALSE;
1524
}
1525
1526
1527
/* callback functions */
1528
1529
static gboolean folderview_button_pressed(GtkWidget *widget,
1530
                                          GdkEventButton *event,
1531
                                          FolderView *folderview)
1532
{
1533
        GtkTreeView *treeview = GTK_TREE_VIEW(widget);
1534
        GtkTreePath *path;
1535
1536
        if (!event)
1537
                return FALSE;
1538
1539
        if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
1540
                                           &path, NULL, NULL, NULL))
1541
                return TRUE;
1542
1543
        if (event->button == 1 || event->button == 2) {
1544
                folderview->open_folder = TRUE;
1545
        } else if (event->button == 3) {
1546
                if (folderview->selected) {
1547
                        folderview->prev_selected =
1548
                                gtk_tree_row_reference_copy
1549
                                        (folderview->selected);
1550
                }
1551
                gtk_tree_selection_select_path(folderview->selection, path);
1552
                folderview_menu_popup(folderview, event);
1553
                gtk_tree_path_free(path);
1554
                return TRUE;
1555
        }
1556
1557
        gtk_tree_path_free(path);
1558
        return FALSE;
1559
}
1560
1561
static gboolean folderview_button_released(GtkWidget *treeview,
1562
                                           GdkEventButton *event,
1563
                                           FolderView *folderview)
1564
{
1565
        folderview->open_folder = FALSE;
1566
        return FALSE;
1567
}
1568
1569
static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1570
                                       FolderView *folderview)
1571
{
1572
        GtkTreePath *opened = NULL, *selected = NULL;
1573
1574
        if (!event) return FALSE;
1575
1576
        switch (event->keyval) {
1577
        case GDK_Return:
1578
                if (folderview->selected) {
1579
                        folderview_select_row_ref(folderview,
1580
                                                  folderview->selected);
1581
                }
1582
                return TRUE;
1583
                break;
1584
        case GDK_space:
1585
                if (folderview->selected) {
1586
                        if (folderview->opened)
1587
                                opened = gtk_tree_row_reference_get_path
1588
                                        (folderview->opened);
1589
                        selected = gtk_tree_row_reference_get_path
1590
                                (folderview->selected);
1591
                        if (opened && selected &&
1592
                            gtk_tree_path_compare(opened, selected) == 0 &&
1593
                            (!folderview->summaryview->folder_item ||
1594
                             folderview->summaryview->folder_item->total == 0))
1595
                                folderview_select_next_unread(folderview);
1596
                        else
1597
                                folderview_select_row_ref(folderview,
1598
                                                          folderview->selected);
1599
                        gtk_tree_path_free(selected);
1600
                        gtk_tree_path_free(opened);
1601
                        return TRUE;
1602
                }
1603
                break;
1604
        default:
1605
                break;
1606
        }
1607
1608
        return FALSE;
1609
}
1610
1611
static gboolean folderview_focus_idle_func(gpointer data)
1612
{
1613
        FolderView *folderview = (FolderView *)data;
1614
1615
        GTK_WIDGET_SET_FLAGS(folderview->treeview, GTK_CAN_FOCUS);
1616
1617
        return FALSE;
1618
}
1619
1620
static void folderview_selection_changed(GtkTreeSelection *selection,
1621
                                         FolderView *folderview)
1622
{
1623
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1624
        FolderItem *item = NULL;
1625
        GtkTreeIter iter;
1626
        GtkTreePath *path;
1627
        gboolean opened;
1628
1629
        if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
1630
                if (folderview->selected) {
1631
                        gtk_tree_row_reference_free(folderview->selected);
1632
                        folderview->selected = NULL;
1633
                }
1634
                return;
1635
        }
1636
1637
        path = gtk_tree_model_get_path(model, &iter);
1638
1639
        gtk_tree_row_reference_free(folderview->selected);
1640
        folderview->selected = gtk_tree_row_reference_new(model, path);
1641
1642
        main_window_set_menu_sensitive(folderview->mainwin);
1643
1644
        if (!folderview->open_folder) {
1645
                gtk_tree_path_free(path);
1646
                return;
1647
        }
1648
        folderview->open_folder = FALSE;
1649
1650
        gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
1651
        if (!item) {
1652
                gtk_tree_path_free(path);
1653
                return;
1654
        }
1655
1656
        if (item->path)
1657
                debug_print(_("Folder %s is selected\n"), item->path);
1658
1659
        if (summary_is_locked(folderview->summaryview)) {
1660
                gtk_tree_path_free(path);
1661
                return;
1662
        }
1663
1664
        if (folderview->opened) {
1665
                GtkTreePath *open_path = NULL;
1666
1667
                open_path = gtk_tree_row_reference_get_path(folderview->opened);
1668
                if (open_path && gtk_tree_path_compare(open_path, path) == 0) {
1669
                        gtk_tree_path_free(open_path);
1670
                        gtk_tree_path_free(path);
1671
                        return;
1672
                }
1673
                gtk_tree_path_free(open_path);
1674
        }
1675
1676
        GTK_EVENTS_FLUSH();
1677
        opened = summary_show(folderview->summaryview, item, FALSE);
1678
1679
        if (opened) {
1680
                gtk_tree_row_reference_free(folderview->opened);
1681
                folderview->opened = gtk_tree_row_reference_new(model, path);
1682
                gtk_tree_view_scroll_to_cell
1683
                        (GTK_TREE_VIEW(folderview->treeview), path, NULL, FALSE,
1684
                         0.0, 0.0);
1685
                if (item->total > 0) {
1686
                        /* don't let GtkTreeView::gtk_tree_view_button_press()
1687
                         * grab focus */
1688
                        GTK_WIDGET_UNSET_FLAGS(folderview->treeview,
1689
                                               GTK_CAN_FOCUS);
1690
                        g_idle_add(folderview_focus_idle_func, folderview);
1691
                }
1692
        } else
1693
                folderview_select_row_ref(folderview, folderview->opened);
1694
1695
        gtk_tree_path_free(path);
1696
}
1697
1698
static void folderview_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter,
1699
                                    GtkTreePath *path, FolderView *folderview)
1700
{
1701
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1702
        FolderItem *item = NULL;
1703
        GtkTreeIter iter_;
1704
        gboolean valid;
1705
1706
        folderview->open_folder = FALSE;
1707
1708
        gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), iter,
1709
                           COL_FOLDER_ITEM, &item, -1);
1710
        g_return_if_fail(item != NULL);
1711
        item->collapsed = FALSE;
1712
        folderview_update_row(folderview, iter);
1713
1714
        valid = gtk_tree_model_iter_children(model, &iter_, iter);
1715
1716
        while (valid) {
1717
                FolderItem *child_item = NULL;
1718
1719
                gtk_tree_model_get(model, &iter_, COL_FOLDER_ITEM, &child_item,
1720
                                   -1);
1721
                if (child_item && child_item->node->children &&
1722
                    !child_item->collapsed) {
1723
                        GtkTreePath *path;
1724
1725
                        path = gtk_tree_model_get_path(model, &iter_);
1726
                        gtk_tree_view_expand_row
1727
                                (GTK_TREE_VIEW(folderview->treeview),
1728
                                 path, FALSE);
1729
                        gtk_tree_path_free(path);
1730
                }
1731
                valid = gtk_tree_model_iter_next(model, &iter_);
1732
        }
1733
}
1734
1735
static void folderview_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter,
1736
                                     GtkTreePath *path, FolderView *folderview)
1737
{
1738
        FolderItem *item = NULL;
1739
1740
        folderview->open_folder = FALSE;
1741
1742
        gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), iter,
1743
                           COL_FOLDER_ITEM, &item, -1);
1744
        g_return_if_fail(item != NULL);
1745
        item->collapsed = TRUE;
1746
        folderview_update_row(folderview, iter);
1747
}
1748
1749
static void folderview_popup_close(GtkMenuShell *menu_shell,
1750
                                   FolderView *folderview)
1751
{
1752
        GtkTreePath *path;
1753
1754
        if (!folderview->prev_selected) return;
1755
1756
        path = gtk_tree_row_reference_get_path(folderview->prev_selected);
1757
        gtk_tree_row_reference_free(folderview->prev_selected);
1758
        folderview->prev_selected = NULL;
1759
        if (!path)
1760
                return;
1761
        gtk_tree_selection_select_path(folderview->selection, path);
1762
        gtk_tree_path_free(path);
1763
}
1764
1765
static void folderview_col_resized(GtkWidget *widget, GtkAllocation *allocation,
1766
                                   FolderView *folderview)
1767
{
1768
        GtkTreeViewColumn *column;
1769
        gint type;
1770
        gint width = allocation->width;
1771
1772
        for (type = 0; type <= COL_TOTAL; type++) {
1773
                column = gtk_tree_view_get_column
1774
                        (GTK_TREE_VIEW(folderview->treeview), type);
1775
                if (column && column->button == widget) {
1776
                        switch (type) {
1777
                        case COL_FOLDER_NAME:
1778
                                prefs_common.folder_col_folder = width;
1779
                                break;
1780
                        case COL_NEW:
1781
                                prefs_common.folder_col_new = width;
1782
                                break;
1783
                        case COL_UNREAD:
1784
                                prefs_common.folder_col_unread = width;
1785
                                break;
1786
                        case COL_TOTAL:
1787
                                prefs_common.folder_col_total = width;
1788
                                break;
1789
                        default:
1790
                                break;
1791
                        }
1792
                        break;
1793
                }
1794
        }
1795
}
1796
1797
static void folderview_download_func(Folder *folder, FolderItem *item,
1798
                                     gpointer data)
1799
{
1800
        GList *list;
1801
1802
        for (list = folderview_list; list != NULL; list = list->next) {
1803
                FolderView *folderview = (FolderView *)list->data;
1804
                MainWindow *mainwin = folderview->mainwin;
1805
                gchar *str;
1806
1807
                str = g_strdup_printf
1808
                        (_("Downloading messages in %s ..."), item->path);
1809
                main_window_progress_set(mainwin,
1810
                                         GPOINTER_TO_INT(data), item->total);
1811
                STATUSBAR_PUSH(mainwin, str);
1812
                STATUSBAR_POP(mainwin);
1813
                g_free(str);
1814
        }
1815
}
1816
1817
static void folderview_download_cb(FolderView *folderview, guint action,
1818
                                   GtkWidget *widget)
1819
{
1820
        MainWindow *mainwin = folderview->mainwin;
1821
        FolderItem *item;
1822
1823
        item = folderview_get_selected_item(folderview);
1824
        if (!item)
1825
                return;
1826
1827
        g_return_if_fail(item->folder != NULL);
1828
1829
        if (!main_window_toggle_online_if_offline(folderview->mainwin))
1830
                return;
1831
1832
        main_window_cursor_wait(mainwin);
1833
        inc_lock();
1834
        main_window_lock(mainwin);
1835
        gtk_widget_set_sensitive(folderview->treeview, FALSE);
1836
        main_window_progress_on(mainwin);
1837
        GTK_EVENTS_FLUSH();
1838
        folder_set_ui_func(item->folder, folderview_download_func, NULL);
1839
        if (folder_item_fetch_all_msg(item) < 0) {
1840
                gchar *name;
1841
1842
                name = trim_string(item->name, 32);
1843
                alertpanel_error(_("Error occurred while downloading messages in `%s'."), name);
1844
                g_free(name);
1845
        }
1846
        folder_set_ui_func(item->folder, NULL, NULL);
1847
        main_window_progress_off(mainwin);
1848
        gtk_widget_set_sensitive(folderview->treeview, TRUE);
1849
        main_window_unlock(mainwin);
1850
        inc_unlock();
1851
        main_window_cursor_normal(mainwin);
1852
        statusbar_pop_all();
1853
}
1854
1855
static void folderview_update_tree_cb(FolderView *folderview, guint action,
1856
                                      GtkWidget *widget)
1857
{
1858
        FolderItem *item;
1859
1860
        item = folderview_get_selected_item(folderview);
1861
        if (!item)
1862
                return;
1863
1864
        g_return_if_fail(item->folder != NULL);
1865
1866
        if (action == 0)
1867
                folderview_check_new(item->folder);
1868
        else
1869
                folderview_rescan_tree(folderview, item->folder);
1870
}
1871
1872
static void folderview_new_folder_cb(FolderView *folderview, guint action,
1873
                                     GtkWidget *widget)
1874
{
1875
        FolderItem *item;
1876
        FolderItem *new_item;
1877
        gchar *new_folder;
1878
        gchar *name;
1879
        gchar *p;
1880
1881
        item = folderview_get_selected_item(folderview);
1882
        if (!item)
1883
                return;
1884
1885
        g_return_if_fail(item->folder != NULL);
1886
1887
        if (FOLDER_TYPE(item->folder) == F_IMAP)
1888
                g_return_if_fail(item->folder->account != NULL);
1889
1890
        if (FOLDER_TYPE(item->folder) == F_IMAP) {
1891
                new_folder = input_dialog
1892
                        (_("New folder"),
1893
                         _("Input the name of new folder:\n"
1894
                           "(if you want to create a folder to store subfolders,\n"
1895
                           " append `/' at the end of the name)"),
1896
                         _("NewFolder"));
1897
        } else {
1898
                new_folder = input_dialog(_("New folder"),
1899
                                          _("Input the name of new folder:"),
1900
                                          _("NewFolder"));
1901
        }
1902
        if (!new_folder) return;
1903
        AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
1904
1905
        p = strchr(new_folder, G_DIR_SEPARATOR);
1906
        if ((p && FOLDER_TYPE(item->folder) != F_IMAP) ||
1907
            (p && FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
1908
                alertpanel_error(_("`%c' can't be included in folder name."),
1909
                                 G_DIR_SEPARATOR);
1910
                return;
1911
        }
1912
1913
        name = trim_string(new_folder, 32);
1914
        AUTORELEASE_STR(name, {g_free(name); return;});
1915
1916
        /* find whether the directory already exists */
1917
        if (folder_find_child_item_by_name(item, new_folder)) {
1918
                alertpanel_error(_("The folder `%s' already exists."), name);
1919
                return;
1920
        }
1921
1922
        new_item = item->folder->klass->create_folder(item->folder, item,
1923
                                                      new_folder);
1924
        if (!new_item) {
1925
                alertpanel_error(_("Can't create the folder `%s'."), name);
1926
                return;
1927
        }
1928
1929
        folderview_append_item(folderview, NULL, new_item);
1930
        folder_write_list();
1931
}
1932
1933
static void folderview_rename_folder_cb(FolderView *folderview, guint action,
1934
                                        GtkWidget *widget)
1935
{
1936
        FolderItem *item;
1937
        gchar *new_folder;
1938
        gchar *name;
1939
        gchar *message;
1940
        gchar *old_path;
1941
        gchar *old_id;
1942
        gchar *new_id;
1943
        GtkTreePath *sel_path;
1944
        GtkTreePath *open_path;
1945
        GtkTreeIter iter;
1946
1947
        item = folderview_get_selected_item(folderview);
1948
        if (!item)
1949
                return;
1950
1951
        g_return_if_fail(item->path != NULL);
1952
        g_return_if_fail(item->folder != NULL);
1953
1954
        name = trim_string(item->name, 32);
1955
        message = g_strdup_printf(_("Input new name for `%s':"), name);
1956
        new_folder = input_dialog(_("Rename folder"), message,
1957
                                  g_basename(item->path));
1958
        g_free(message);
1959
        g_free(name);
1960
        if (!new_folder) return;
1961
        AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
1962
1963
        if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1964
                alertpanel_error(_("`%c' can't be included in folder name."),
1965
                                 G_DIR_SEPARATOR);
1966
                return;
1967
        }
1968
1969
        if (folder_find_child_item_by_name(item->parent, new_folder)) {
1970
                name = trim_string(new_folder, 32);
1971
                alertpanel_error(_("The folder `%s' already exists."), name);
1972
                g_free(name);
1973
                return;
1974
        }
1975
1976
        Xstrdup_a(old_path, item->path, {g_free(new_folder); return;});
1977
        old_id = folder_item_get_identifier(item);
1978
1979
        if (item->folder->klass->rename_folder(item->folder, item,
1980
                                               new_folder) < 0) {
1981
                g_free(old_id);
1982
                return;
1983
        }
1984
1985
        if (folder_get_default_folder() == item->folder)
1986
                prefs_filter_rename_path(old_path, item->path);
1987
        new_id = folder_item_get_identifier(item);
1988
        prefs_filter_rename_path(old_id, new_id);
1989
        g_free(old_id);
1990
        g_free(new_id);
1991
1992
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
1993
        open_path = gtk_tree_row_reference_get_path(folderview->opened);
1994
        if (sel_path) {
1995
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
1996
                                        &iter, sel_path);
1997
                folderview_update_row(folderview, &iter);
1998
        }
1999
        if (sel_path && open_path &&
2000
            (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2001
             gtk_tree_path_is_ancestor(sel_path, open_path))) {
2002
                GtkTreeRowReference *row;
2003
2004
                row = gtk_tree_row_reference_copy(folderview->opened);
2005
                folderview_unselect(folderview);
2006
                folderview_select_row_ref(folderview, row);
2007
                gtk_tree_row_reference_free(row);
2008
        }
2009
        gtk_tree_path_free(open_path);
2010
        gtk_tree_path_free(sel_path);
2011
2012
        folder_write_list();
2013
}
2014
2015
static void folderview_delete_folder_cb(FolderView *folderview, guint action,
2016
                                        GtkWidget *widget)
2017
{
2018
        Folder *folder;
2019
        FolderItem *item;
2020
        gchar *message, *name;
2021
        AlertValue avalue;
2022
        gchar *old_path;
2023
        gchar *old_id;
2024
        GtkTreePath *sel_path, *open_path;
2025
        GtkTreeIter iter;
2026
2027
        item = folderview_get_selected_item(folderview);
2028
        if (!item)
2029
                return;
2030
2031
        g_return_if_fail(item->path != NULL);
2032
        g_return_if_fail(item->folder != NULL);
2033
2034
        folder = item->folder;
2035
2036
        name = trim_string(item->name, 32);
2037
        AUTORELEASE_STR(name, {g_free(name); return;});
2038
        message = g_strdup_printf
2039
                (_("All folders and messages under `%s' will be permanently deleted.\n"
2040
                   "Recovery will not be possible.\n\n"
2041
                   "Do you really want to delete?"), name);
2042
        avalue = alertpanel(_("Delete folder"), message,
2043
                            _("Yes"), _("+No"), NULL);
2044
        g_free(message);
2045
        if (avalue != G_ALERTDEFAULT) return;
2046
2047
        Xstrdup_a(old_path, item->path, return);
2048
        old_id = folder_item_get_identifier(item);
2049
2050
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2051
        g_return_if_fail(sel_path != NULL);
2052
        open_path = gtk_tree_row_reference_get_path(folderview->opened);
2053
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
2054
                                sel_path);
2055
        if (sel_path && open_path &&
2056
            (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2057
             gtk_tree_path_is_ancestor(sel_path, open_path))) {
2058
                summary_clear_all(folderview->summaryview);
2059
                gtk_tree_row_reference_free(folderview->opened);
2060
                folderview->opened = NULL;
2061
        }
2062
        gtk_tree_path_free(open_path);
2063
        gtk_tree_path_free(sel_path);
2064
2065
        if (folder->klass->remove_folder(folder, item) < 0) {
2066
                alertpanel_error(_("Can't remove the folder `%s'."), name);
2067
                g_free(old_id);
2068
                return;
2069
        }
2070
2071
        if (folder_get_default_folder() == folder)
2072
                prefs_filter_delete_path(old_path);
2073
        prefs_filter_delete_path(old_id);
2074
        g_free(old_id);
2075
2076
        gtk_tree_store_remove(folderview->store, &iter);
2077
2078
        folder_write_list();
2079
}
2080
2081
static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2082
                                      GtkWidget *widget)
2083
{
2084
        FolderItem *item;
2085
        Folder *folder;
2086
        GtkTreePath *sel_path, *open_path;
2087
2088
        item = folderview_get_selected_item(folderview);
2089
        if (!item)
2090
                return;
2091
2092
        g_return_if_fail(item->path != NULL);
2093
        g_return_if_fail(item->folder != NULL);
2094
2095
        folder = item->folder;
2096
2097
        if (folder->trash != item) return;
2098
        if (item->stype != F_TRASH) return;
2099
2100
        if (alertpanel(_("Empty trash"), _("Empty all messages in trash?"),
2101
                       GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
2102
                return;
2103
2104
        procmsg_empty_trash(folder->trash);
2105
        statusbar_pop_all();
2106
        folderview_update_item(folder->trash, TRUE);
2107
2108
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2109
        open_path = gtk_tree_row_reference_get_path(folderview->opened);
2110
        if (open_path && sel_path &&
2111
            gtk_tree_path_compare(open_path, sel_path) == 0)
2112
                gtk_widget_grab_focus(folderview->treeview);
2113
        gtk_tree_path_free(open_path);
2114
        gtk_tree_path_free(sel_path);
2115
}
2116
2117
static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
2118
                                         GtkWidget *widget)
2119
{
2120
        FolderItem *item;
2121
        gchar *name;
2122
        gchar *message;
2123
        AlertValue avalue;
2124
        GtkTreePath *sel_path;
2125
        GtkTreeIter iter;
2126
2127
        item = folderview_get_selected_item(folderview);
2128
        if (!item)
2129
                return;
2130
2131
        g_return_if_fail(item->folder != NULL);
2132
        if (item->parent) return;
2133
2134
        name = trim_string(item->folder->name, 32);
2135
        message = g_strdup_printf
2136
                (_("Really remove the mailbox `%s' ?\n"
2137
                   "(The messages are NOT deleted from the disk)"), name);
2138
        avalue = alertpanel(_("Remove mailbox"), message,
2139
                            _("Yes"), _("+No"), NULL);
2140
        g_free(message);
2141
        g_free(name);
2142
        if (avalue != G_ALERTDEFAULT) return;
2143
2144
        if (folderview->summaryview->folder_item &&
2145
            folderview->summaryview->folder_item->folder == item->folder) {
2146
                summary_clear_all(folderview->summaryview);
2147
                gtk_tree_row_reference_free(folderview->opened);
2148
                folderview->opened = NULL;
2149
        }
2150
        folder_destroy(item->folder);
2151
2152
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2153
        if (sel_path) {
2154
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2155
                                        &iter, sel_path);
2156
                gtk_tree_path_free(sel_path);
2157
                gtk_tree_store_remove(folderview->store, &iter);
2158
        }
2159
2160
        folder_write_list();
2161
}
2162
2163
static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2164
                                         GtkWidget *widget)
2165
{
2166
        FolderItem *item;
2167
        PrefsAccount *account;
2168
        gchar *name;
2169
        gchar *message;
2170
        AlertValue avalue;
2171
        GtkTreePath *sel_path;
2172
        GtkTreeIter iter;
2173
2174
        item = folderview_get_selected_item(folderview);
2175
        if (!item)
2176
                return;
2177
2178
        g_return_if_fail(item->folder != NULL);
2179
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2180
        g_return_if_fail(item->folder->account != NULL);
2181
2182
        name = trim_string(item->folder->name, 32);
2183
        message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"), name);
2184
        avalue = alertpanel(_("Delete IMAP4 account"), message,
2185
                            _("Yes"), _("+No"), NULL);
2186
        g_free(message);
2187
        g_free(name);
2188
2189
        if (avalue != G_ALERTDEFAULT) return;
2190
2191
        if (folderview->summaryview->folder_item &&
2192
            folderview->summaryview->folder_item->folder == item->folder) {
2193
                summary_clear_all(folderview->summaryview);
2194
                gtk_tree_row_reference_free(folderview->opened);
2195
                folderview->opened = NULL;
2196
        }
2197
2198
        account = item->folder->account;
2199
        folder_destroy(item->folder);
2200
        account_destroy(account);
2201
2202
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2203
        if (sel_path) {
2204
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2205
                                        &iter, sel_path);
2206
                gtk_tree_path_free(sel_path);
2207
                gtk_tree_store_remove(folderview->store, &iter);
2208
        }
2209
2210
        account_set_menu();
2211
        main_window_reflect_prefs_all();
2212
        folder_write_list();
2213
}
2214
2215
static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2216
                                         GtkWidget *widget)
2217
{
2218
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2219
        Folder *folder;
2220
        FolderItem *item;
2221
        FolderItem *rootitem = NULL;
2222
        FolderItem *newitem;
2223
        GSList *new_subscr;
2224
        GSList *cur;
2225
        GNode *gnode;
2226
        GtkTreePath *server_path;
2227
        GtkTreeIter iter, root;
2228
2229
        item = folderview_get_selected_item(folderview);
2230
        if (!item)
2231
                return;
2232
2233
        folder = item->folder;
2234
        g_return_if_fail(folder != NULL);
2235
        g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
2236
        g_return_if_fail(folder->account != NULL);
2237
2238
        server_path = gtk_tree_row_reference_get_path(folderview->selected);
2239
        g_return_if_fail(server_path != NULL);
2240
        gtk_tree_model_get_iter(model, &iter, server_path);
2241
        gtk_tree_path_free(server_path);
2242
2243
        if (!gtk_tree_model_iter_parent(model, &root, &iter))
2244
                root = iter;
2245
2246
        gtk_tree_model_get(model, &root, COL_FOLDER_ITEM, &rootitem, -1);
2247
2248
        new_subscr = grouplist_dialog(folder);
2249
2250
        /* remove unsubscribed newsgroups */
2251
        for (gnode = folder->node->children; gnode != NULL; ) {
2252
                GNode *next = gnode->next;
2253
                GtkTreeIter found;
2254
2255
                item = FOLDER_ITEM(gnode->data);
2256
                if (g_slist_find_custom(new_subscr, item->path,
2257
                                        (GCompareFunc)g_ascii_strcasecmp)
2258
                    != NULL) {
2259
                        gnode = next;
2260
                        continue;
2261
                }
2262
2263
                if (!gtkut_tree_model_find_by_column_data
2264
                        (model, &found, &root, COL_FOLDER_ITEM, item)) {
2265
                        gnode = next;
2266
                        continue;
2267
                }
2268
2269
                if (folderview->summaryview->folder_item == item) {
2270
                        summary_clear_all(folderview->summaryview);
2271
                        gtk_tree_row_reference_free(folderview->opened);
2272
                        folderview->opened = NULL;
2273
                }
2274
2275
                folder_item_remove(item);
2276
                gtk_tree_store_remove(folderview->store, &found);
2277
2278
                gnode = next;
2279
        }
2280
2281
        /* add subscribed newsgroups */
2282
        for (cur = new_subscr; cur != NULL; cur = cur->next) {
2283
                gchar *name = (gchar *)cur->data;
2284
2285
                if (folder_find_child_item_by_name(rootitem, name) != NULL)
2286
                        continue;
2287
2288
                newitem = folder_item_new(name, name);
2289
                folder_item_append(rootitem, newitem);
2290
                folderview_append_item(folderview, NULL, newitem);
2291
        }
2292
2293
        if (new_subscr) {
2294
                server_path = gtk_tree_model_get_path(model, &root);
2295
                gtk_tree_view_expand_row(GTK_TREE_VIEW(folderview->treeview),
2296
                                         server_path, FALSE);
2297
                gtk_tree_path_free(server_path);
2298
        }
2299
2300
        slist_free_strings(new_subscr);
2301
        g_slist_free(new_subscr);
2302
2303
        folder_write_list();
2304
}
2305
2306
static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2307
                                        GtkWidget *widget)
2308
{
2309
        FolderItem *item;
2310
        gchar *name;
2311
        gchar *message;
2312
        AlertValue avalue;
2313
        GtkTreePath *sel_path, *open_path;
2314
        GtkTreeIter iter;
2315
2316
        item = folderview_get_selected_item(folderview);
2317
        if (!item)
2318
                return;
2319
2320
        g_return_if_fail(item->folder != NULL);
2321
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2322
        g_return_if_fail(item->folder->account != NULL);
2323
2324
        name = trim_string_before(item->path, 32);
2325
        message = g_strdup_printf(_("Really delete newsgroup `%s'?"), name);
2326
        avalue = alertpanel(_("Delete newsgroup"), message,
2327
                            _("Yes"), _("+No"), NULL);
2328
        g_free(message);
2329
        g_free(name);
2330
        if (avalue != G_ALERTDEFAULT) return;
2331
2332
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2333
        g_return_if_fail(sel_path != NULL);
2334
        open_path = gtk_tree_row_reference_get_path(folderview->opened);
2335
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
2336
                                sel_path);
2337
        if (open_path && sel_path &&
2338
            gtk_tree_path_compare(open_path, sel_path) == 0) {
2339
                summary_clear_all(folderview->summaryview);
2340
                gtk_tree_row_reference_free(folderview->opened);
2341
                folderview->opened = NULL;
2342
        }
2343
        gtk_tree_path_free(open_path);
2344
        gtk_tree_path_free(sel_path);
2345
2346
        folder_item_remove(item);
2347
        gtk_tree_store_remove(folderview->store, &iter);
2348
        folder_write_list();
2349
}
2350
2351
static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2352
                                         GtkWidget *widget)
2353
{
2354
        FolderItem *item;
2355
        PrefsAccount *account;
2356
        gchar *name;
2357
        gchar *message;
2358
        AlertValue avalue;
2359
        GtkTreePath *sel_path;
2360
        GtkTreeIter iter;
2361
2362
        item = folderview_get_selected_item(folderview);
2363
        if (!item)
2364
                return;
2365
2366
        g_return_if_fail(item->folder != NULL);
2367
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2368
        g_return_if_fail(item->folder->account != NULL);
2369
2370
        name = trim_string(item->folder->name, 32);
2371
        message = g_strdup_printf(_("Really delete news account `%s'?"), name);
2372
        avalue = alertpanel(_("Delete news account"), message,
2373
                            _("Yes"), _("+No"), NULL);
2374
        g_free(message);
2375
        g_free(name);
2376
2377
        if (avalue != G_ALERTDEFAULT) return;
2378
2379
        if (folderview->summaryview->folder_item &&
2380
            folderview->summaryview->folder_item->folder == item->folder) {
2381
                summary_clear_all(folderview->summaryview);
2382
                gtk_tree_row_reference_free(folderview->opened);
2383
                folderview->opened = NULL;
2384
        }
2385
2386
        account = item->folder->account;
2387
        folder_destroy(item->folder);
2388
        account_destroy(account);
2389
2390
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2391
        if (sel_path) {
2392
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2393
                                        &iter, sel_path);
2394
                gtk_tree_path_free(sel_path);
2395
                gtk_tree_store_remove(folderview->store, &iter);
2396
        }
2397
2398
        account_set_menu();
2399
        main_window_reflect_prefs_all();
2400
        folder_write_list();
2401
}
2402
2403
static void folderview_search_cb(FolderView *folderview, guint action,
2404
                                 GtkWidget *widget)
2405
{
2406
        summary_search(folderview->summaryview);
2407
}
2408
2409
static void folderview_property_cb(FolderView *folderview, guint action,
2410
                                   GtkWidget *widget)
2411
{
2412
        FolderItem *item;
2413
2414
        item = folderview_get_selected_item(folderview);
2415
        if (!item)
2416
                return;
2417
2418
        g_return_if_fail(item->folder != NULL);
2419
2420
        if (item->parent == NULL && item->folder->account)
2421
                account_open(item->folder->account);
2422
        else
2423
                prefs_folder_item_open(item);
2424
}
2425
2426
static gint auto_expand_timeout(gpointer data)
2427
{
2428
        FolderView *folderview = data;
2429
        GtkTreeView *treeview = GTK_TREE_VIEW(folderview->treeview);
2430
        GtkTreePath *path = NULL;
2431
2432
        gtk_tree_view_get_drag_dest_row(treeview, &path, NULL);
2433
2434
        if (path) {
2435
                gtk_tree_view_expand_row(treeview, path, FALSE);
2436
                gtk_tree_path_free(path);
2437
                folderview->expand_timeout = 0;
2438
2439
                return FALSE;
2440
        } else
2441
                return TRUE;
2442
}
2443
2444
static void remove_auto_expand_timeout(FolderView *folderview)
2445
{
2446
        if (folderview->expand_timeout != 0) {
2447
                g_source_remove(folderview->expand_timeout);
2448
                folderview->expand_timeout = 0;
2449
        }
2450
}
2451
2452
static gint auto_scroll_timeout(gpointer data)
2453
{
2454
        FolderView *folderview = data;
2455
2456
        gtkut_tree_view_vertical_autoscroll
2457
                (GTK_TREE_VIEW(folderview->treeview));
2458
2459
        return TRUE;
2460
}
2461
2462
static void remove_auto_scroll_timeout(FolderView *folderview)
2463
{
2464
        if (folderview->scroll_timeout != 0) {
2465
                g_source_remove(folderview->scroll_timeout);
2466
                folderview->scroll_timeout = 0;
2467
        }
2468
}
2469
2470
static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
2471
                                          GdkDragContext *context,
2472
                                          gint            x,
2473
                                          gint            y,
2474
                                          guint           time,
2475
                                          FolderView     *folderview)
2476
{
2477
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2478
        GtkTreePath *path = NULL, *prev_path = NULL;
2479
        GtkTreeIter iter;
2480
        FolderItem *item = NULL, *src_item = NULL;
2481
        gboolean acceptable = FALSE;
2482
2483
        if (gtk_tree_view_get_dest_row_at_pos
2484
                (GTK_TREE_VIEW(widget), x, y, &path, NULL)) {
2485
                gtk_tree_model_get_iter(model, &iter, path);
2486
                gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
2487
                src_item = folderview->summaryview->folder_item;
2488
                if (src_item && src_item != item)
2489
                        acceptable = FOLDER_ITEM_CAN_ADD(item);
2490
        } else
2491
                remove_auto_expand_timeout(folderview);
2492
2493
        gtk_tree_view_get_drag_dest_row(GTK_TREE_VIEW(widget),
2494
                                        &prev_path, NULL);
2495
        if (!path || (prev_path && gtk_tree_path_compare(path, prev_path) != 0))
2496
                remove_auto_expand_timeout(folderview);
2497
        if (prev_path)
2498
                gtk_tree_path_free(prev_path);
2499
2500
        gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), path,
2501
                                        GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
2502
2503
        if (path) {
2504
                if (folderview->expand_timeout == 0) {
2505
                        folderview->expand_timeout =
2506
                                g_timeout_add(1000, auto_expand_timeout,
2507
                                              folderview);
2508
                } else if (folderview->scroll_timeout == 0) {
2509
                        folderview->scroll_timeout =
2510
                                g_timeout_add(150, auto_scroll_timeout,
2511
                                              folderview);
2512
                }
2513
        }
2514
2515
        if (acceptable) {
2516
                if ((context->actions & GDK_ACTION_MOVE) != 0 &&
2517
                    FOLDER_ITEM_CAN_ADD(src_item))
2518
                        gdk_drag_status(context, GDK_ACTION_MOVE, time);
2519
                else if ((context->actions & GDK_ACTION_COPY) != 0)
2520
                        gdk_drag_status(context, GDK_ACTION_COPY, time);
2521
                else if ((context->actions & GDK_ACTION_LINK) != 0)
2522
                        gdk_drag_status(context, GDK_ACTION_LINK, time);
2523
                else
2524
                        gdk_drag_status(context, 0, time);
2525
        } else
2526
                gdk_drag_status(context, 0, time);
2527
2528
        if (path)
2529
                gtk_tree_path_free(path);
2530
2531
        return TRUE;
2532
}
2533
2534
static void folderview_drag_leave_cb(GtkWidget      *widget,
2535
                                     GdkDragContext *context,
2536
                                     guint           time,
2537
                                     FolderView     *folderview)
2538
{
2539
        remove_auto_expand_timeout(folderview);
2540
        remove_auto_scroll_timeout(folderview);
2541
2542
        gtk_tree_view_set_drag_dest_row
2543
                (GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
2544
}
2545
2546
static void folderview_drag_received_cb(GtkWidget        *widget,
2547
                                        GdkDragContext   *context,
2548
                                        gint              x,
2549
                                        gint              y,
2550
                                        GtkSelectionData *data,
2551
                                        guint             info,
2552
                                        guint             time,
2553
                                        FolderView       *folderview)
2554
{
2555
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2556
        GtkTreePath *path = NULL;
2557
        GtkTreeIter iter;
2558
        FolderItem *item = NULL, *src_item;
2559
2560
        remove_auto_expand_timeout(folderview);
2561
        remove_auto_scroll_timeout(folderview);
2562
2563
        if (!gtk_tree_view_get_dest_row_at_pos
2564
                (GTK_TREE_VIEW(widget), x, y, &path, NULL))
2565
                return;
2566
2567
        gtk_tree_model_get_iter(model, &iter, path);
2568
        gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
2569
        src_item = folderview->summaryview->folder_item;
2570
2571
        if (FOLDER_ITEM_CAN_ADD(item) && src_item && src_item != item) {
2572
                if ((context->actions & GDK_ACTION_MOVE) != 0 &&
2573
                    FOLDER_ITEM_CAN_ADD(src_item)) {
2574
                        summary_move_selected_to(folderview->summaryview, item);
2575
                        context->action = 0;
2576
                        gtk_drag_finish(context, TRUE, FALSE, time);
2577
                } else if ((context->actions & GDK_ACTION_COPY) != 0) {
2578
                        summary_copy_selected_to(folderview->summaryview, item);
2579
                        gtk_drag_finish(context, TRUE, FALSE, time);
2580
                } else
2581
                        gtk_drag_finish(context, FALSE, FALSE, time);
2582
        } else
2583
                gtk_drag_finish(context, FALSE, FALSE, time);
2584
2585
        gtk_tree_path_free(path);
2586
}
2587
2588
static gint folderview_folder_name_compare(GtkTreeModel *model,
2589
                                           GtkTreeIter *a, GtkTreeIter *b,
2590
                                           gpointer data)
2591
{
2592
        FolderItem *item_a = NULL, *item_b = NULL;
2593
2594
        gtk_tree_model_get(model, a, COL_FOLDER_ITEM, &item_a, -1);
2595
        gtk_tree_model_get(model, b, COL_FOLDER_ITEM, &item_b, -1);
2596
2597
        return folder_item_compare(item_a, item_b);
2598
}