Statistics
| Revision:

root / src / folderview.c @ 2164

History | View | Annotate | Download (87.4 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2009 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 "query_search.h"
49
#include "inputdialog.h"
50
#include "subscribedialog.h"
51
#include "foldersel.h"
52
#include "manage_window.h"
53
#include "alertpanel.h"
54
#include "menu.h"
55
#include "stock_pixmap.h"
56
#include "statusbar.h"
57
#include "procmsg.h"
58
#include "utils.h"
59
#include "gtkutils.h"
60
#include "trayicon.h"
61
#include "prefs_common.h"
62
#include "prefs_account.h"
63
#include "prefs_folder_item.h"
64
#include "prefs_search_folder.h"
65
#include "filter.h"
66
#include "account.h"
67
#include "account_dialog.h"
68
#include "folder.h"
69
#include "inc.h"
70
#include "send_message.h"
71
#include "virtual.h"
72
#include "plugin.h"
73

    
74
enum
75
{
76
        COL_FOLDER_NAME,
77
        COL_NEW,
78
        COL_UNREAD,
79
        COL_TOTAL,
80
        COL_FOLDER_ITEM,
81
        COL_PIXBUF,
82
        COL_PIXBUF_OPEN,
83
        COL_FOREGROUND,
84
        COL_BOLD,
85
        N_COLS
86
};
87

    
88
#define COL_FOLDER_WIDTH        150
89
#define COL_NUM_WIDTH                32
90

    
91
#define STATUSBAR_PUSH(mainwin, str) \
92
{ \
93
        gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
94
                           mainwin->folderview_cid, str); \
95
        gtkut_widget_draw_now(mainwin->statusbar); \
96
}
97

    
98
#define STATUSBAR_POP(mainwin) \
99
{ \
100
        gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
101
                          mainwin->folderview_cid); \
102
}
103

    
104
static GList *folderview_list = NULL;
105

    
106
static GdkPixbuf *inbox_pixbuf;
107
static GdkPixbuf *outbox_pixbuf;
108
static GdkPixbuf *folder_pixbuf;
109
static GdkPixbuf *folderopen_pixbuf;
110
static GdkPixbuf *foldernoselect_pixbuf;
111
static GdkPixbuf *draft_pixbuf;
112
static GdkPixbuf *trash_pixbuf;
113
static GdkPixbuf *virtual_pixbuf;
114

    
115
static void folderview_set_columns        (FolderView        *folderview);
116

    
117
static void folderview_select_row        (FolderView        *folderview,
118
                                         GtkTreeIter        *iter);
119
static void folderview_select_row_ref        (FolderView        *folderview,
120
                                         GtkTreeRowReference *row);
121

    
122
static void folderview_set_folders        (FolderView        *folderview);
123
static void folderview_append_folder        (FolderView        *folderview,
124
                                         Folder                *folder);
125

    
126
static void folderview_update_row        (FolderView        *folderview,
127
                                         GtkTreeIter        *iter);
128
static void folderview_update_row_all        (FolderView        *folderview);
129

    
130
static gint folderview_folder_name_compare        (GtkTreeModel        *model,
131
                                                 GtkTreeIter        *a,
132
                                                 GtkTreeIter        *b,
133
                                                 gpointer         data);
134

    
135
/* callback functions */
136
static gboolean folderview_button_pressed        (GtkWidget        *treeview,
137
                                                 GdkEventButton        *event,
138
                                                 FolderView        *folderview);
139
static gboolean folderview_button_released        (GtkWidget        *treeview,
140
                                                 GdkEventButton        *event,
141
                                                 FolderView        *folderview);
142

    
143
static gboolean folderview_key_pressed        (GtkWidget        *widget,
144
                                         GdkEventKey        *event,
145
                                         FolderView        *folderview);
146

    
147
static void folderview_selection_changed(GtkTreeSelection        *selection,
148
                                         FolderView                *folderview);
149

    
150
static void folderview_row_expanded        (GtkTreeView                *treeview,
151
                                         GtkTreeIter                *iter,
152
                                         GtkTreePath                *path,
153
                                         FolderView                *folderview);
154
static void folderview_row_collapsed        (GtkTreeView                *treeview,
155
                                         GtkTreeIter                *iter,
156
                                         GtkTreePath                *path,
157
                                         FolderView                *folderview);
158

    
159
static void folderview_popup_close        (GtkMenuShell        *menu_shell,
160
                                         FolderView        *folderview);
161

    
162
static void folderview_col_resized        (GtkWidget        *widget,
163
                                         GtkAllocation        *allocation,
164
                                         FolderView        *folderview);
165

    
166
static void folderview_download_cb        (FolderView        *folderview,
167
                                         guint                 action,
168
                                         GtkWidget        *widget);
169

    
170
static void folderview_update_tree_cb        (FolderView        *folderview,
171
                                         guint                 action,
172
                                         GtkWidget        *widget);
173

    
174
static void folderview_update_summary_cb(FolderView        *folderview,
175
                                         guint                 action,
176
                                         GtkWidget        *widget);
177

    
178
static void folderview_mark_all_read_cb        (FolderView        *folderview,
179
                                         guint                 action,
180
                                         GtkWidget        *widget);
181
static void folderview_send_queue_cb        (FolderView        *folderview,
182
                                         guint                 action,
183
                                         GtkWidget        *widget);
184

    
185
static void folderview_new_folder_cb        (FolderView        *folderview,
186
                                         guint                 action,
187
                                         GtkWidget        *widget);
188
static void folderview_rename_folder_cb        (FolderView        *folderview,
189
                                         guint                 action,
190
                                         GtkWidget        *widget);
191
static void folderview_move_folder_cb        (FolderView        *folderview,
192
                                         guint                 action,
193
                                         GtkWidget        *widget);
194
static void folderview_delete_folder_cb        (FolderView        *folderview,
195
                                         guint                 action,
196
                                         GtkWidget        *widget);
197
static void folderview_empty_trash_cb        (FolderView        *folderview,
198
                                         guint                 action,
199
                                         GtkWidget        *widget);
200
static void folderview_remove_mailbox_cb(FolderView        *folderview,
201
                                         guint                 action,
202
                                         GtkWidget        *widget);
203

    
204
static void folderview_rm_imap_server_cb (FolderView        *folderview,
205
                                          guint                 action,
206
                                          GtkWidget        *widget);
207

    
208
static void folderview_new_news_group_cb(FolderView        *folderview,
209
                                         guint                 action,
210
                                         GtkWidget        *widget);
211
static void folderview_rm_news_group_cb        (FolderView        *folderview,
212
                                         guint                 action,
213
                                         GtkWidget        *widget);
214
static void folderview_rm_news_server_cb(FolderView        *folderview,
215
                                         guint                 action,
216
                                         GtkWidget        *widget);
217

    
218
static void folderview_search_cb        (FolderView        *folderview,
219
                                         guint                 action,
220
                                         GtkWidget        *widget);
221

    
222
static void folderview_property_cb        (FolderView        *folderview,
223
                                         guint                 action,
224
                                         GtkWidget        *widget);
225

    
226
static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
227
                                          GdkDragContext *context,
228
                                          gint            x,
229
                                          gint            y,
230
                                          guint           time,
231
                                          FolderView     *folderview);
232
static void folderview_drag_leave_cb     (GtkWidget        *widget,
233
                                          GdkDragContext   *context,
234
                                          guint             time,
235
                                          FolderView       *folderview);
236
static void folderview_drag_received_cb  (GtkWidget        *widget,
237
                                          GdkDragContext   *context,
238
                                          gint              x,
239
                                          gint              y,
240
                                          GtkSelectionData *data,
241
                                          guint             info,
242
                                          guint             time,
243
                                          FolderView       *folderview);
244

    
245
static GtkTargetEntry folderview_drag_types[] =
246
{
247
        {"text/plain", GTK_TARGET_SAME_APP, 0}
248
};
249

    
250
static GtkItemFactoryEntry folderview_mail_popup_entries[] =
251
{
252
        {N_("/Create _new folder..."),        NULL, folderview_new_folder_cb, 0, NULL},
253
        {N_("/_Rename folder..."),        NULL, folderview_rename_folder_cb, 0, NULL},
254
        {N_("/_Move folder..."),        NULL, folderview_move_folder_cb, 0, NULL},
255
        {N_("/_Delete folder"),                NULL, folderview_delete_folder_cb, 0, NULL},
256
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
257
        {N_("/Empty _trash"),                NULL, folderview_empty_trash_cb, 0, NULL},
258
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
259
        {N_("/_Check for new messages"),
260
                                        NULL, folderview_update_tree_cb, 0, NULL},
261
        {N_("/R_ebuild folder tree"),        NULL, folderview_update_tree_cb, 1, NULL},
262
        {N_("/_Update summary"),        NULL, folderview_update_summary_cb, 0, NULL},
263
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
264
        {N_("/Mar_k all read"),                NULL, folderview_mark_all_read_cb, 0, NULL},
265
        {N_("/Send _queued messages"),        NULL, folderview_send_queue_cb, 0, NULL},
266
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
267
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
268
        {N_("/Ed_it search condition..."),
269
                                        NULL, folderview_search_cb, 0, NULL},
270
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
271
};
272

    
273
static GtkItemFactoryEntry folderview_imap_popup_entries[] =
274
{
275
        {N_("/Create _new folder..."),        NULL, folderview_new_folder_cb,    0, NULL},
276
        {N_("/_Rename folder..."),        NULL, folderview_rename_folder_cb, 0, NULL},
277
        {N_("/_Move folder..."),        NULL, folderview_move_folder_cb, 0, NULL},
278
        {N_("/_Delete folder"),                NULL, folderview_delete_folder_cb, 0, NULL},
279
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
280
        {N_("/Empty _trash"),                NULL, folderview_empty_trash_cb, 0, NULL},
281
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
282
        {N_("/Down_load"),                NULL, folderview_download_cb, 0, NULL},
283
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
284
        {N_("/_Check for new messages"),
285
                                        NULL, folderview_update_tree_cb, 0, NULL},
286
        {N_("/R_ebuild folder tree"),        NULL, folderview_update_tree_cb, 1, NULL},
287
        {N_("/_Update summary"),        NULL, folderview_update_summary_cb, 0, NULL},
288
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
289
        {N_("/Mar_k all read"),                NULL, folderview_mark_all_read_cb, 0, NULL},
290
        {N_("/Send _queued messages"),        NULL, folderview_send_queue_cb, 0, NULL},
291
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
292
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
293
        {N_("/Ed_it search condition..."),
294
                                        NULL, folderview_search_cb, 0, NULL},
295
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
296
};
297

    
298
static GtkItemFactoryEntry folderview_news_popup_entries[] =
299
{
300
        {N_("/Su_bscribe to newsgroup..."),
301
                                        NULL, folderview_new_news_group_cb, 0, NULL},
302
        {N_("/_Remove newsgroup"),        NULL, folderview_rm_news_group_cb, 0, NULL},
303
        {N_("/_Rename folder..."),        NULL, folderview_rename_folder_cb, 0, NULL},
304
        {N_("/_Delete folder"),                NULL, folderview_delete_folder_cb, 0, NULL},
305
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
306
        {N_("/Down_load"),                NULL, folderview_download_cb, 0, NULL},
307
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
308
        {N_("/_Check for new messages"),
309
                                        NULL, folderview_update_tree_cb, 0, NULL},
310
        {N_("/_Update summary"),        NULL, folderview_update_summary_cb, 0, NULL},
311
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
312
        {N_("/Mar_k all read"),                NULL, folderview_mark_all_read_cb, 0, NULL},
313
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
314
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
315
        {N_("/Ed_it search condition..."),
316
                                        NULL, folderview_search_cb, 0, NULL},
317
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
318
};
319

    
320

    
321
FolderView *folderview_create(void)
322
{
323
        FolderView *folderview;
324
        GtkWidget *scrolledwin;
325
        GtkWidget *treeview;
326
        GtkTreeStore *store;
327
        GtkTreeSelection *selection;
328
        GtkTreeViewColumn *column;
329
        GtkCellRenderer *renderer;
330
        GtkWidget *mail_popup;
331
        GtkWidget *news_popup;
332
        GtkWidget *imap_popup;
333
        GtkItemFactory *mail_factory;
334
        GtkItemFactory *news_factory;
335
        GtkItemFactory *imap_factory;
336
        gint n_entries;
337

    
338
        debug_print(_("Creating folder view...\n"));
339
        folderview = g_new0(FolderView, 1);
340

    
341
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
342
        gtk_scrolled_window_set_policy
343
                (GTK_SCROLLED_WINDOW(scrolledwin),
344
                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
345
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
346
                                            GTK_SHADOW_IN);
347
        gtk_widget_set_size_request(scrolledwin,
348
                                    prefs_common.folderview_width,
349
                                    prefs_common.folderview_height);
350

    
351
        store = gtk_tree_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING,
352
                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER,
353
                                   GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF,
354
                                   GDK_TYPE_COLOR, G_TYPE_INT);
355
        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),
356
                                        COL_FOLDER_NAME,
357
                                        folderview_folder_name_compare,
358
                                        NULL, NULL);
359

    
360
        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
361
        g_object_unref(G_OBJECT(store));
362
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
363
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), FALSE);
364
        gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview),
365
                                        COL_FOLDER_NAME);
366
        gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), FALSE);
367
        /* g_object_set(treeview, "fixed-height-mode", TRUE, NULL); */
368

    
369
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
370
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
371

    
372
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
373

    
374
        /* create folder icon + name column */
375
        column = gtk_tree_view_column_new();
376
        gtk_tree_view_column_set_spacing(column, 2);
377
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
378
        gtk_tree_view_column_set_fixed_width
379
                (column, prefs_common.folder_col_folder);
380
        gtk_tree_view_column_set_resizable(column, TRUE);
381

    
382
        renderer = gtk_cell_renderer_pixbuf_new();
383
        g_object_set(renderer, "ypad", 0, NULL);
384
        gtk_tree_view_column_pack_start(column, renderer, FALSE);
385
        gtk_tree_view_column_set_title(column, _("Folder"));
386
        gtk_tree_view_column_set_attributes
387
                (column, renderer,
388
                 "pixbuf", COL_PIXBUF,
389
                 "pixbuf-expander-open", COL_PIXBUF_OPEN,
390
                 "pixbuf-expander-closed", COL_PIXBUF,
391
                 NULL);
392

    
393
        renderer = gtk_cell_renderer_text_new();
394
#if GTK_CHECK_VERSION(2, 6, 0)
395
        g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ypad", 0,
396
                     NULL);
397
#else
398
        g_object_set(renderer, "ypad", 0, NULL);
399
#endif
400
        gtk_tree_view_column_pack_start(column, renderer, TRUE);
401
        gtk_tree_view_column_set_attributes(column, renderer,
402
                                            "text", COL_FOLDER_NAME,
403
                                            "foreground-gdk", COL_FOREGROUND,
404
                                            "weight", COL_BOLD,
405
                                            NULL);
406

    
407
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
408
        gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
409
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
410
                         G_CALLBACK(folderview_col_resized), folderview);
411

    
412
        renderer = gtk_cell_renderer_text_new();
413
        g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
414
        column = gtk_tree_view_column_new_with_attributes
415
                (_("New"), renderer, "text", COL_NEW,
416
                 "foreground-gdk", COL_FOREGROUND,
417
                 "weight", COL_BOLD, NULL);
418
        gtk_tree_view_column_set_alignment(column, 1.0);
419
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
420
        gtk_tree_view_column_set_fixed_width
421
                (column, prefs_common.folder_col_new);
422
        gtk_tree_view_column_set_min_width(column, 8);
423
        gtk_tree_view_column_set_resizable(column, TRUE);
424
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
425
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
426
                         G_CALLBACK(folderview_col_resized), folderview);
427

    
428
        renderer = gtk_cell_renderer_text_new();
429
        g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
430
        column = gtk_tree_view_column_new_with_attributes
431
                (_("Unread"), renderer, "text", COL_UNREAD,
432
                 "foreground-gdk", COL_FOREGROUND,
433
                 "weight", COL_BOLD, NULL);
434
        gtk_tree_view_column_set_alignment(column, 1.0);
435
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
436
        gtk_tree_view_column_set_fixed_width
437
                (column, prefs_common.folder_col_unread);
438
        gtk_tree_view_column_set_min_width(column, 8);
439
        gtk_tree_view_column_set_resizable(column, TRUE);
440
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
441
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
442
                         G_CALLBACK(folderview_col_resized), folderview);
443

    
444
        renderer = gtk_cell_renderer_text_new();
445
        g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
446
        column = gtk_tree_view_column_new_with_attributes
447
                (_("Total"), renderer, "text", COL_TOTAL,
448
                 "foreground-gdk", COL_FOREGROUND,
449
                 "weight", COL_BOLD, NULL);
450
        gtk_tree_view_column_set_alignment(column, 1.0);
451
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
452
        gtk_tree_view_column_set_fixed_width
453
                (column, prefs_common.folder_col_total);
454
        gtk_tree_view_column_set_min_width(column, 8);
455
        gtk_tree_view_column_set_resizable(column, TRUE);
456
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
457
        g_signal_connect(G_OBJECT(column->button), "size-allocate",
458
                         G_CALLBACK(folderview_col_resized), folderview);
459

    
460
        gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
461
                                             COL_FOLDER_NAME,
462
                                             GTK_SORT_ASCENDING);
463

    
464
        /* popup menu */
465
        n_entries = sizeof(folderview_mail_popup_entries) /
466
                sizeof(folderview_mail_popup_entries[0]);
467
        mail_popup = menu_create_items(folderview_mail_popup_entries,
468
                                       n_entries,
469
                                       "<MailFolder>", &mail_factory,
470
                                       folderview);
471
        n_entries = sizeof(folderview_imap_popup_entries) /
472
                sizeof(folderview_imap_popup_entries[0]);
473
        imap_popup = menu_create_items(folderview_imap_popup_entries,
474
                                       n_entries,
475
                                       "<IMAPFolder>", &imap_factory,
476
                                       folderview);
477
        n_entries = sizeof(folderview_news_popup_entries) /
478
                sizeof(folderview_news_popup_entries[0]);
479
        news_popup = menu_create_items(folderview_news_popup_entries,
480
                                       n_entries,
481
                                       "<NewsFolder>", &news_factory,
482
                                       folderview);
483

    
484
        g_signal_connect(G_OBJECT(treeview), "button_press_event",
485
                         G_CALLBACK(folderview_button_pressed), folderview);
486
        g_signal_connect(G_OBJECT(treeview), "button_release_event",
487
                         G_CALLBACK(folderview_button_released), folderview);
488
        g_signal_connect(G_OBJECT(treeview), "key_press_event",
489
                         G_CALLBACK(folderview_key_pressed), folderview);
490

    
491
        g_signal_connect(G_OBJECT(selection), "changed",
492
                         G_CALLBACK(folderview_selection_changed), folderview);
493

    
494
        g_signal_connect_after(G_OBJECT(treeview), "row-expanded",
495
                               G_CALLBACK(folderview_row_expanded),
496
                               folderview);
497
        g_signal_connect_after(G_OBJECT(treeview), "row-collapsed",
498
                               G_CALLBACK(folderview_row_collapsed),
499
                               folderview);
500

    
501
        g_signal_connect(G_OBJECT(mail_popup), "selection_done",
502
                         G_CALLBACK(folderview_popup_close), folderview);
503
        g_signal_connect(G_OBJECT(imap_popup), "selection_done",
504
                         G_CALLBACK(folderview_popup_close), folderview);
505
        g_signal_connect(G_OBJECT(news_popup), "selection_done",
506
                         G_CALLBACK(folderview_popup_close), folderview);
507

    
508
        /* drop callback */
509
        gtk_drag_dest_set(treeview, GTK_DEST_DEFAULT_ALL,
510
                          folderview_drag_types, 1,
511
                          GDK_ACTION_MOVE | GDK_ACTION_COPY);
512
        g_signal_connect(G_OBJECT(treeview), "drag-motion",
513
                         G_CALLBACK(folderview_drag_motion_cb),
514
                         folderview);
515
        g_signal_connect(G_OBJECT(treeview), "drag-leave",
516
                         G_CALLBACK(folderview_drag_leave_cb),
517
                         folderview);
518
        g_signal_connect(G_OBJECT(treeview), "drag-data-received",
519
                         G_CALLBACK(folderview_drag_received_cb),
520
                         folderview);
521

    
522
        folderview->scrolledwin  = scrolledwin;
523
        folderview->treeview     = treeview;
524
        folderview->store        = store;
525
        folderview->selection    = selection;
526
        folderview->mail_popup   = mail_popup;
527
        folderview->mail_factory = mail_factory;
528
        folderview->imap_popup   = imap_popup;
529
        folderview->imap_factory = imap_factory;
530
        folderview->news_popup   = news_popup;
531
        folderview->news_factory = news_factory;
532

    
533
        folderview->display_folder_unread = prefs_common.display_folder_unread;
534

    
535
        folderview_set_columns(folderview);
536

    
537
        gtk_widget_show_all(scrolledwin);
538

    
539
        folderview_list = g_list_append(folderview_list, folderview);
540

    
541
        return folderview;
542
}
543

    
544
void folderview_init(FolderView *folderview)
545
{
546
        GtkWidget *treeview = folderview->treeview;
547

    
548
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_INBOX, &inbox_pixbuf);
549
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_OUTBOX, &outbox_pixbuf);
550
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DIR_CLOSE, &folder_pixbuf);
551
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DIR_OPEN, &folderopen_pixbuf);
552
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DIR_NOSELECT,
553
                         &foldernoselect_pixbuf);
554
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DRAFT, &draft_pixbuf);
555
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_TRASH, &trash_pixbuf);
556
        stock_pixbuf_gdk(treeview, STOCK_PIXMAP_GROUP, &virtual_pixbuf);
557
}
558

    
559
void folderview_reflect_prefs(FolderView *folderview)
560
{
561
        folderview_set_columns(folderview);
562
        if (folderview->display_folder_unread !=
563
            prefs_common.display_folder_unread) {
564
                folderview->display_folder_unread =
565
                        prefs_common.display_folder_unread;
566
                folderview_update_row_all(folderview);
567
        }
568
}
569

    
570
FolderView *folderview_get(void)
571
{
572
        return (FolderView *)folderview_list->data;
573
}
574

    
575
void folderview_set(FolderView *folderview)
576
{
577
        MainWindow *mainwin = folderview->mainwin;
578
        GtkTreeIter iter;
579

    
580
        debug_print(_("Setting folder info...\n"));
581
        STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
582

    
583
        main_window_cursor_wait(mainwin);
584

    
585
        folderview_unselect(folderview);
586

    
587
        gtk_tree_store_clear(folderview->store);
588

    
589
        folderview_set_folders(folderview);
590

    
591
        if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(folderview->store),
592
                                          &iter))
593
                folderview_select_row(folderview, &iter);
594

    
595
        main_window_cursor_normal(mainwin);
596
        STATUSBAR_POP(mainwin);
597
}
598

    
599
void folderview_set_all(void)
600
{
601
        GList *list;
602

    
603
        for (list = folderview_list; list != NULL; list = list->next)
604
                folderview_set((FolderView *)list->data);
605
}
606

    
607
static void folderview_set_columns(FolderView *folderview)
608
{
609
        GtkTreeView *treeview = GTK_TREE_VIEW(folderview->treeview);
610
        GtkTreeViewColumn *column;
611

    
612
        column = gtk_tree_view_get_column(treeview, COL_NEW);
613
        gtk_tree_view_column_set_visible
614
                (column, prefs_common.display_folder_num_columns);
615
        column = gtk_tree_view_get_column(treeview, COL_UNREAD);
616
        gtk_tree_view_column_set_visible
617
                (column, prefs_common.display_folder_num_columns);
618
        column = gtk_tree_view_get_column(treeview, COL_TOTAL);
619
        gtk_tree_view_column_set_visible
620
                (column, prefs_common.display_folder_num_columns);
621
}
622

    
623
void folderview_select(FolderView *folderview, FolderItem *item)
624
{
625
        GtkTreeIter iter;
626

    
627
        if (!item) return;
628

    
629
        if (gtkut_tree_model_find_by_column_data
630
                (GTK_TREE_MODEL(folderview->store), &iter, NULL,
631
                 COL_FOLDER_ITEM, item))
632
                folderview_select_row(folderview, &iter);
633
}
634

    
635
static void folderview_select_row(FolderView *folderview, GtkTreeIter *iter)
636
{
637
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
638
        GtkTreePath *path;
639

    
640
        g_return_if_fail(iter != NULL);
641

    
642
        path = gtk_tree_model_get_path(model, iter);
643

    
644
        gtkut_tree_view_expand_parent_all(GTK_TREE_VIEW(folderview->treeview),
645
                                          iter);
646

    
647
        folderview->open_folder = TRUE;
648
        gtk_tree_view_set_cursor(GTK_TREE_VIEW(folderview->treeview), path,
649
                                 NULL, FALSE);
650
        if (folderview->summaryview->folder_item &&
651
            folderview->summaryview->folder_item->total > 0)
652
                gtk_widget_grab_focus(folderview->summaryview->treeview);
653
        else
654
                gtk_widget_grab_focus(folderview->treeview);
655

    
656
        gtk_tree_path_free(path);
657
}
658

    
659
static void folderview_select_row_ref(FolderView *folderview,
660
                                      GtkTreeRowReference *row)
661
{
662
        GtkTreePath *path;
663
        GtkTreeIter iter;
664

    
665
        if (!row) return;
666

    
667
        path = gtk_tree_row_reference_get_path(row);
668
        if (!path)
669
                return;
670
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
671
        gtk_tree_path_free(path);
672

    
673
        folderview_select_row(folderview, &iter);
674
}
675

    
676
void folderview_unselect(FolderView *folderview)
677
{
678
        if (folderview->selected) {
679
                gtk_tree_row_reference_free(folderview->selected);
680
                folderview->selected = NULL;
681
        }
682
        if (folderview->opened) {
683
                gtk_tree_row_reference_free(folderview->opened);
684
                folderview->opened = NULL;
685
        }
686
}
687

    
688
static gboolean folderview_find_next_unread(GtkTreeModel *model,
689
                                            GtkTreeIter *next,
690
                                            GtkTreeIter *iter)
691
{
692
        FolderItem *item;
693
        GtkTreeIter iter_;
694
        gboolean valid;
695

    
696
        if (iter) {
697
                iter_ = *iter;
698
                valid = gtkut_tree_model_next(model, &iter_);
699
        } else
700
                valid = gtk_tree_model_get_iter_first(model, &iter_);
701

    
702
        while (valid) {
703
                item = NULL;
704
                gtk_tree_model_get(model, &iter_, COL_FOLDER_ITEM, &item, -1);
705
                if (item && item->unread > 0 && item->stype != F_TRASH) {
706
                        if (next)
707
                                *next = iter_;
708
                        return TRUE;
709
                }
710

    
711
                valid = gtkut_tree_model_next(model, &iter_);
712
        }
713

    
714
        return FALSE;
715
}
716

    
717
void folderview_select_next_unread(FolderView *folderview)
718
{
719
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
720
        GtkTreeIter iter, next;
721
        gboolean remember_last;
722

    
723
        if (folderview->opened) {
724
                GtkTreePath *path;
725

    
726
                path = gtk_tree_row_reference_get_path(folderview->opened);
727
                if (!path)
728
                        return;
729
                gtk_tree_model_get_iter(model, &iter, path);
730
                gtk_tree_path_free(path);
731
        } else {
732
                if (!gtk_tree_model_get_iter_first(model, &iter))
733
                        return;
734
        }
735
        if (folderview_find_next_unread(model, &next, &iter)) {
736
                remember_last = prefs_common.remember_last_selected;
737
                prefs_common.remember_last_selected = FALSE;
738
                folderview_select_row(folderview, &next);
739
                prefs_common.remember_last_selected = remember_last;
740
                return;
741
        }
742

    
743
        if (!folderview->opened)
744
                return;
745

    
746
        /* search again from the first row */
747
        if (folderview_find_next_unread(model, &next, NULL)) {
748
                remember_last = prefs_common.remember_last_selected;
749
                prefs_common.remember_last_selected = FALSE;
750
                folderview_select_row(folderview, &next);
751
                prefs_common.remember_last_selected = remember_last;
752
        }
753
}
754

    
755
FolderItem *folderview_get_selected_item(FolderView *folderview)
756
{
757
        GtkTreePath *path;
758
        GtkTreeIter iter;
759
        FolderItem *item = NULL;
760

    
761
        if (!folderview->selected)
762
                return NULL;
763

    
764
        path = gtk_tree_row_reference_get_path(folderview->selected);
765
        if (!path)
766
                return NULL;
767
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
768
        gtk_tree_path_free(path);
769
        gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), &iter,
770
                           COL_FOLDER_ITEM, &item, -1);
771

    
772
        return item;
773
}
774

    
775
void folderview_set_opened_item(FolderView *folderview, FolderItem *item)
776
{
777
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
778
        GtkTreeIter iter;
779
        GtkTreePath *path;
780

    
781
        gtk_tree_row_reference_free(folderview->opened);
782
        folderview->opened = NULL;
783

    
784
        if (!item)
785
                return;
786

    
787
        if (gtkut_tree_model_find_by_column_data
788
                 (model, &iter, NULL, COL_FOLDER_ITEM, item)) {
789
                path = gtk_tree_model_get_path(model, &iter);
790
                folderview->opened = gtk_tree_row_reference_new(model, path);
791
                gtk_tree_path_free(path);
792
        }
793
}
794

    
795
void folderview_update_opened_msg_num(FolderView *folderview)
796
{
797
        GtkTreePath *path;
798
        GtkTreeIter iter;
799

    
800
        if (!folderview->opened)
801
                return;
802

    
803
        path = gtk_tree_row_reference_get_path(folderview->opened);
804
        if (!path)
805
                return;
806
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
807
        gtk_tree_path_free(path);
808

    
809
        folderview_update_row(folderview, &iter);
810
}
811

    
812
gboolean folderview_append_item(FolderView *folderview, GtkTreeIter *iter,
813
                                FolderItem *item, gboolean expand_parent)
814
{
815
        FolderItem *parent_item;
816
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
817
        GtkTreeIter iter_, child;
818
        GtkTreeIter *iter_p = &iter_;
819

    
820
        g_return_val_if_fail(item != NULL, FALSE);
821
        g_return_val_if_fail(item->folder != NULL, FALSE);
822

    
823
        parent_item = item->parent;
824

    
825
        if (!parent_item)
826
                iter_p = NULL;
827
        else if (!gtkut_tree_model_find_by_column_data
828
                (model, iter_p, NULL, COL_FOLDER_ITEM, parent_item))
829
                return FALSE;
830

    
831
        if (!gtkut_tree_model_find_by_column_data
832
                (model, &child, iter_p, COL_FOLDER_ITEM, item)) {
833
                gtk_tree_store_append(folderview->store, &child, iter_p);
834
                gtk_tree_store_set(folderview->store, &child,
835
                                   COL_FOLDER_NAME, item->name,
836
                                   COL_FOLDER_ITEM, item,
837
                                   -1);
838
                folderview_update_row(folderview, &child);
839
                if (iter)
840
                        *iter = child;
841
                if (expand_parent && iter_p) {
842
                        GtkTreePath *path;
843

    
844
                        path = gtk_tree_model_get_path(model, iter_p);
845
                        gtk_tree_view_expand_row
846
                                (GTK_TREE_VIEW(folderview->treeview),
847
                                 path, FALSE);
848
                        gtk_tree_path_free(path);
849
                }
850
                return TRUE;
851
        }
852

    
853
        return FALSE;
854
}
855

    
856
static void folderview_set_folders(FolderView *folderview)
857
{
858
        GList *list;
859

    
860
        list = folder_get_list();
861

    
862
        for (; list != NULL; list = list->next)
863
                folderview_append_folder(folderview, FOLDER(list->data));
864
}
865

    
866
static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
867
                                      gpointer data)
868
{
869
        GList *list;
870
        gchar *rootpath;
871

    
872
        if (FOLDER_IS_LOCAL(folder))
873
                rootpath = LOCAL_FOLDER(folder)->rootpath;
874
        else if (FOLDER_TYPE(folder) == F_IMAP && folder->account &&
875
                 folder->account->recv_server)
876
                rootpath = folder->account->recv_server;
877
        else if (FOLDER_TYPE(folder) == F_NEWS && folder->account &&
878
                 folder->account->nntp_server)
879
                rootpath = folder->account->nntp_server;
880
        else
881
                return;
882

    
883
        for (list = folderview_list; list != NULL; list = list->next) {
884
                FolderView *folderview = (FolderView *)list->data;
885
                MainWindow *mainwin = folderview->mainwin;
886
                gchar *str;
887

    
888
                if (item->path)
889
                        str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
890
                                              rootpath, G_DIR_SEPARATOR,
891
                                              item->path);
892
                else
893
                        str = g_strdup_printf(_("Scanning folder %s ..."),
894
                                              rootpath);
895

    
896
                STATUSBAR_PUSH(mainwin, str);
897
                STATUSBAR_POP(mainwin);
898
                g_free(str);
899
        }
900
}
901

    
902
static GtkWidget *label_window_create(const gchar *str)
903
{
904
        GtkWidget *window;
905
        GtkWidget *label;
906

    
907
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
908
        gtk_widget_set_size_request(window, 380, 60);
909
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
910
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
911
        gtk_window_set_title(GTK_WINDOW(window), str);
912
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
913
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
914
        manage_window_set_transient(GTK_WINDOW(window));
915

    
916
        label = gtk_label_new(str);
917
        gtk_container_add(GTK_CONTAINER(window), label);
918
        gtk_widget_show(label);
919

    
920
        gtk_widget_show(window);
921

    
922
        return window;
923
}
924

    
925
static void folderview_rescan_tree(FolderView *folderview, Folder *folder)
926
{
927
        GtkWidget *window;
928
        AlertValue avalue;
929

    
930
        g_return_if_fail(folder != NULL);
931

    
932
        if (!folder->klass->scan_tree) return;
933

    
934
        avalue = alertpanel
935
                (_("Rebuild folder tree"),
936
                 _("The folder tree will be rebuilt. Continue?"),
937
                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
938
        if (avalue != G_ALERTDEFAULT) return;
939

    
940
        if (!FOLDER_IS_LOCAL(folder) &&
941
            !main_window_toggle_online_if_offline(folderview->mainwin))
942
                return;
943

    
944
        inc_lock();
945
        window = label_window_create(_("Rebuilding folder tree..."));
946

    
947
        summary_show(folderview->summaryview, NULL, FALSE);
948
        GTK_EVENTS_FLUSH();
949

    
950
        folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
951
        if (folder->klass->scan_tree(folder) < 0)
952
                alertpanel_error(_("Rebuilding of the folder tree failed."));
953
        folder_set_ui_func(folder, NULL, NULL);
954

    
955
        folder_write_list();
956
        folderview_set_all();
957
        statusbar_pop_all();
958

    
959
        gtk_widget_destroy(window);
960
        inc_unlock();
961
}
962

    
963
gint folderview_check_new(Folder *folder)
964
{
965
        FolderItem *item;
966
        FolderView *folderview;
967
        GtkTreeModel *model;
968
        GtkTreeIter iter;
969
        gboolean valid;
970
        gint prev_new, prev_unread, n_updated = 0;
971

    
972
        folderview = (FolderView *)folderview_list->data;
973
        model = GTK_TREE_MODEL(folderview->store);
974

    
975
        if (folder && FOLDER_IS_REMOTE(folder)) {
976
                if (!main_window_toggle_online_if_offline(folderview->mainwin))
977
                        return 0;
978
        }
979

    
980
        inc_lock();
981
        main_window_lock(folderview->mainwin);
982
        gtk_widget_set_sensitive(folderview->treeview, FALSE);
983
        GTK_EVENTS_FLUSH();
984

    
985
        for (valid = gtk_tree_model_get_iter_first(model, &iter);
986
             valid; valid = gtkut_tree_model_next(model, &iter)) {
987
                item = NULL;
988
                gtk_tree_model_get(model, &iter,
989
                                   COL_FOLDER_ITEM, &item, -1);
990
                if (!item || !item->path || !item->folder) continue;
991
                if (item->stype == F_VIRTUAL) continue;
992
                if (item->no_select) continue;
993
                if (folder && folder != item->folder) continue;
994
                if (!folder && FOLDER_IS_REMOTE(item->folder)) continue;
995

    
996
                prev_new = item->new;
997
                prev_unread = item->unread;
998
                folderview_scan_tree_func(item->folder, item, NULL);
999
                if (folder_item_scan(item) < 0) {
1000
                        if (folder && FOLDER_IS_REMOTE(folder) &&
1001
                            REMOTE_FOLDER(folder)->session == NULL)
1002
                                break;
1003
                }
1004
                folderview_update_row(folderview, &iter);
1005
                if (prev_unread < item->unread)
1006
                        n_updated += item->unread - prev_unread;
1007
                else if (prev_new < item->new)
1008
                        n_updated += item->new - prev_new;
1009
        }
1010

    
1011
        gtk_widget_set_sensitive(folderview->treeview, TRUE);
1012
        main_window_unlock(folderview->mainwin);
1013
        inc_unlock();
1014
        statusbar_pop_all();
1015

    
1016
        folder_write_list();
1017

    
1018
        return n_updated;
1019
}
1020

    
1021
gint folderview_check_new_item(FolderItem *item)
1022
{
1023
        Folder *folder;
1024
        FolderView *folderview;
1025
        GtkTreeModel *model;
1026
        GtkTreeIter iter;
1027
        gint prev_new, prev_unread, n_updated = 0;
1028

    
1029
        g_return_val_if_fail(item != NULL, 0);
1030
        g_return_val_if_fail(item->folder != NULL, 0);
1031

    
1032
        if (!item->path || item->no_select)
1033
                return 0;
1034

    
1035
        folderview = (FolderView *)folderview_list->data;
1036
        model = GTK_TREE_MODEL(folderview->store);
1037

    
1038
        folder = item->folder;
1039

    
1040
        if (!FOLDER_IS_LOCAL(folder)) {
1041
                if (!main_window_toggle_online_if_offline(folderview->mainwin))
1042
                        return 0;
1043
        }
1044

    
1045
        if (!gtkut_tree_model_find_by_column_data
1046
                (model, &iter, NULL, COL_FOLDER_ITEM, item))
1047
                return 0;
1048

    
1049
        inc_lock();
1050
        main_window_lock(folderview->mainwin);
1051
        gtk_widget_set_sensitive(folderview->treeview, FALSE);
1052
        GTK_EVENTS_FLUSH();
1053

    
1054
        prev_new = item->new;
1055
        prev_unread = item->unread;
1056
        folderview_scan_tree_func(folder, item, NULL);
1057
        folder_item_scan(item);
1058
        folderview_update_row(folderview, &iter);
1059
        if (prev_unread < item->unread)
1060
                n_updated = item->unread - prev_unread;
1061
        else if (prev_new < item->new)
1062
                n_updated = item->new - prev_new;
1063

    
1064
        gtk_widget_set_sensitive(folderview->treeview, TRUE);
1065
        main_window_unlock(folderview->mainwin);
1066
        inc_unlock();
1067
        statusbar_pop_all();
1068

    
1069
        folder_write_list();
1070

    
1071
        return n_updated;
1072
}
1073

    
1074
gint folderview_check_new_all(void)
1075
{
1076
        GList *list;
1077
        GtkWidget *window;
1078
        FolderView *folderview;
1079
        gint n_updated = 0;
1080

    
1081
        folderview = (FolderView *)folderview_list->data;
1082

    
1083
        inc_lock();
1084
        main_window_lock(folderview->mainwin);
1085
        window = label_window_create
1086
                (_("Checking for new messages in all folders..."));
1087

    
1088
        list = folder_get_list();
1089
        for (; list != NULL; list = list->next) {
1090
                Folder *folder = list->data;
1091

    
1092
                n_updated += folderview_check_new(folder);
1093
        }
1094

    
1095
        gtk_widget_destroy(window);
1096
        main_window_unlock(folderview->mainwin);
1097
        inc_unlock();
1098

    
1099
        return n_updated;
1100
}
1101

    
1102
static gboolean folderview_search_new_recursive(GtkTreeModel *model,
1103
                                                GtkTreeIter *iter)
1104
{
1105
        FolderItem *item = NULL;
1106
        GtkTreeIter iter_;
1107
        gboolean valid;
1108

    
1109
        if (iter) {
1110
                gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
1111
                if (item) {
1112
                        if (item->new > 0 ||
1113
                            (item->stype == F_QUEUE && item->total > 0))
1114
                                return TRUE;
1115
                }
1116
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
1117
        } else
1118
                valid = gtk_tree_model_get_iter_first(model, &iter_);
1119

    
1120
        while (valid) {
1121
                if (folderview_search_new_recursive(model, &iter_) == TRUE)
1122
                        return TRUE;
1123
                valid = gtk_tree_model_iter_next(model, &iter_);
1124
        }
1125

    
1126
        return FALSE;
1127
}
1128

    
1129
static gboolean folderview_have_new_children(FolderView *folderview,
1130
                                             GtkTreeIter *iter)
1131
{
1132
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1133
        GtkTreeIter iter_;
1134
        gboolean valid;
1135

    
1136
        if (iter)
1137
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
1138
        else
1139
                valid = gtk_tree_model_get_iter_first(model, &iter_);
1140

    
1141
        while (valid) {
1142
                if (folderview_search_new_recursive(model, &iter_) == TRUE)
1143
                        return TRUE;
1144
                valid = gtk_tree_model_iter_next(model, &iter_);
1145
        }
1146

    
1147
        return FALSE;
1148
}
1149

    
1150
static gboolean folderview_search_unread_recursive(GtkTreeModel *model,
1151
                                                   GtkTreeIter *iter)
1152
{
1153
        FolderItem *item = NULL;
1154
        GtkTreeIter iter_;
1155
        gboolean valid;
1156

    
1157
        if (iter) {
1158
                gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
1159
                if (item) {
1160
                        if (item->stype == F_TRASH)
1161
                                return FALSE;
1162
                        if (item->unread > 0 ||
1163
                            (item->stype == F_QUEUE && item->total > 0))
1164
                                return TRUE;
1165
                }
1166
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
1167
        } else
1168
                valid = gtk_tree_model_get_iter_first(model, &iter_);
1169

    
1170
        while (valid) {
1171
                if (folderview_search_unread_recursive(model, &iter_) == TRUE)
1172
                        return TRUE;
1173
                valid = gtk_tree_model_iter_next(model, &iter_);
1174
        }
1175

    
1176
        return FALSE;
1177
}
1178

    
1179
static gboolean folderview_have_unread_children(FolderView *folderview,
1180
                                                GtkTreeIter *iter)
1181
{
1182
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1183
        GtkTreeIter iter_;
1184
        gboolean valid;
1185

    
1186
        if (iter)
1187
                valid = gtk_tree_model_iter_children(model, &iter_, iter);
1188
        else
1189
                valid = gtk_tree_model_get_iter_first(model, &iter_);
1190

    
1191
        while (valid) {
1192
                if (folderview_search_unread_recursive(model, &iter_) == TRUE)
1193
                        return TRUE;
1194
                valid = gtk_tree_model_iter_next(model, &iter_);
1195
        }
1196

    
1197
        return FALSE;
1198
}
1199

    
1200
static void folderview_update_row(FolderView *folderview, GtkTreeIter *iter)
1201
{
1202
        GtkTreeStore *store = folderview->store;
1203
        GtkTreeModel *model = GTK_TREE_MODEL(store);
1204
        GtkTreePath *path;
1205
        GtkTreeIter parent;
1206
        FolderItem *item = NULL;
1207
        GdkPixbuf *pixbuf, *open_pixbuf;
1208
        gchar *name, *str;
1209
        gchar new_s[11], unread_s[11], total_s[11];
1210
        gboolean add_unread_mark;
1211
        gboolean use_color;
1212
        PangoWeight weight = PANGO_WEIGHT_NORMAL;
1213
        GdkColor *foreground = NULL;
1214

    
1215
        gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
1216
        g_return_if_fail(item != NULL);
1217

    
1218
        switch (item->stype) {
1219
        case F_INBOX:
1220
                pixbuf = open_pixbuf = inbox_pixbuf;
1221
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1222
                                !strcmp2(item->name, INBOX_DIR) ? _("Inbox") :
1223
                                item->name);
1224
                break;
1225
        case F_OUTBOX:
1226
                pixbuf = open_pixbuf = outbox_pixbuf;
1227
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1228
                                !strcmp2(item->name, OUTBOX_DIR) ? _("Sent") :
1229
                                item->name);
1230
                break;
1231
        case F_QUEUE:
1232
                pixbuf = open_pixbuf = outbox_pixbuf;
1233
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1234
                                !strcmp2(item->name, QUEUE_DIR) ? _("Queue") :
1235
                                item->name);
1236
                break;
1237
        case F_TRASH:
1238
                pixbuf = open_pixbuf = trash_pixbuf;
1239
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1240
                                !strcmp2(item->name, TRASH_DIR) ? _("Trash") :
1241
                                item->name);
1242
                break;
1243
        case F_DRAFT:
1244
                pixbuf = open_pixbuf = draft_pixbuf;
1245
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1246
                                !strcmp2(item->name, DRAFT_DIR) ? _("Drafts") :
1247
                                item->name);
1248
                break;
1249
#if 0
1250
        case F_JUNK:
1251
                pixbuf = folder_pixbuf;
1252
                open_pixbuf = folderopen_pixbuf;
1253
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1254
                                !strcmp2(item->name, JUNK_DIR) ? _("Junk") :
1255
                                item->name);
1256
                break;
1257
#endif
1258
        case F_VIRTUAL:
1259
                pixbuf = open_pixbuf = virtual_pixbuf;
1260
                name = g_strdup(item->name);
1261
                break;
1262
        default:
1263
                if (item->no_select) {
1264
                        pixbuf = open_pixbuf = foldernoselect_pixbuf;
1265
                } else {
1266
                        pixbuf = folder_pixbuf;
1267
                        open_pixbuf = folderopen_pixbuf;
1268
                }
1269

    
1270
                if (!item->parent) {
1271
                        switch (FOLDER_TYPE(item->folder)) {
1272
                        case F_MH:
1273
                                name = " (MH)"; break;
1274
                        case F_IMAP:
1275
                                name = " (IMAP4)"; break;
1276
                        case F_NEWS:
1277
                                name = " (News)"; break;
1278
                        default:
1279
                                name = "";
1280
                        }
1281
                        name = g_strconcat(item->name, name, NULL);
1282
                } else {
1283
                        if (FOLDER_TYPE(item->folder) == F_NEWS &&
1284
                            item->path &&
1285
                            !strcmp2(item->name, item->path))
1286
                                name = get_abbrev_newsgroup_name
1287
                                        (item->path,
1288
                                         prefs_common.ng_abbrev_len);
1289
                        else
1290
                                name = g_strdup(item->name);
1291
                }
1292
        }
1293

    
1294
        path = gtk_tree_model_get_path(model, iter);
1295
        if (!gtk_tree_view_row_expanded
1296
                (GTK_TREE_VIEW(folderview->treeview), path) &&
1297
            folderview_have_unread_children(folderview, iter))
1298
                add_unread_mark = TRUE;
1299
        else
1300
                add_unread_mark = FALSE;
1301
        gtk_tree_path_free(path);
1302

    
1303
        if (item->stype == F_QUEUE && item->total > 0 &&
1304
            folderview->display_folder_unread) {
1305
                str = g_strdup_printf("%s (%d%s)", name, item->total,
1306
                                      add_unread_mark ? "+" : "");
1307
                g_free(name);
1308
                name = str;
1309
        } else if ((item->unread > 0 || add_unread_mark) &&
1310
                   folderview->display_folder_unread) {
1311
                if (item->unread > 0)
1312
                        str = g_strdup_printf("%s (%d%s)", name, item->unread,
1313
                                              add_unread_mark ? "+" : "");
1314
                else
1315
                        str = g_strdup_printf("%s (+)", name);
1316
                g_free(name);
1317
                name = str;
1318
        }
1319

    
1320
        if (!item->parent) {
1321
                strcpy(new_s, "-");
1322
                strcpy(unread_s, "-");
1323
                strcpy(total_s, "-");
1324
        } else {
1325
                itos_buf(new_s, item->new);
1326
                itos_buf(unread_s, item->unread);
1327
                itos_buf(total_s, item->total);
1328
        }
1329

    
1330
        if (item->stype == F_OUTBOX || item->stype == F_DRAFT ||
1331
            item->stype == F_TRASH) {
1332
                use_color = FALSE;
1333
        } else if (item->stype == F_QUEUE) {
1334
                /* highlight queue folder if there are any messages */
1335
                use_color = (item->total > 0);
1336
                if (item->total > 0)
1337
                        weight = PANGO_WEIGHT_BOLD;
1338
        } else {
1339
                /* if unread messages exist, print with bold font */
1340
                if ((item->unread > 0) || add_unread_mark)
1341
                        weight = PANGO_WEIGHT_BOLD;
1342
                /* if new messages exist, print with colored letter */
1343
                use_color =
1344
                        (item->new > 0) ||
1345
                        (add_unread_mark &&
1346
                         folderview_have_new_children(folderview, iter));
1347
        }
1348

    
1349
        if (item->no_select)
1350
                foreground = &folderview->color_noselect;
1351
        else if (use_color)
1352
                foreground = &folderview->color_new;
1353

    
1354
        gtk_tree_store_set(store, iter,
1355
                           COL_FOLDER_NAME, name,
1356
                           COL_NEW, new_s,
1357
                           COL_UNREAD, unread_s,
1358
                           COL_TOTAL, total_s,
1359
                           COL_FOLDER_ITEM, item,
1360
                           COL_PIXBUF, pixbuf,
1361
                           COL_PIXBUF_OPEN, open_pixbuf,
1362
                           COL_FOREGROUND, foreground,
1363
                           COL_BOLD, weight,
1364
                           -1);
1365
        g_free(name);
1366

    
1367
        item->updated = FALSE;
1368

    
1369
        if (gtkut_tree_view_find_collapsed_parent
1370
                (GTK_TREE_VIEW(folderview->treeview), &parent, iter))
1371
                folderview_update_row(folderview, &parent);
1372
}
1373

    
1374
static void folderview_update_row_all(FolderView *folderview)
1375
{
1376
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1377
        GtkTreeIter iter;
1378
        gboolean valid;
1379

    
1380
        valid = gtk_tree_model_get_iter_first(model, &iter);
1381

    
1382
        while (valid) {
1383
                folderview_update_row(folderview, &iter);
1384
                valid = gtkut_tree_model_next(model, &iter);
1385
        }
1386
}
1387

    
1388
void folderview_update_item(FolderItem *item, gboolean update_summary)
1389
{
1390
        FolderView *folderview;
1391
        GtkTreeIter iter;
1392

    
1393
        g_return_if_fail(item != NULL);
1394

    
1395
        folderview = folderview_get();
1396

    
1397
        if (gtkut_tree_model_find_by_column_data
1398
                (GTK_TREE_MODEL(folderview->store), &iter, NULL,
1399
                 COL_FOLDER_ITEM, item)) {
1400
                folderview_update_row(folderview, &iter);
1401
                if (update_summary &&
1402
                    folderview->summaryview->folder_item == item)
1403
                        summary_show(folderview->summaryview, item, FALSE);
1404
        }
1405
}
1406

    
1407
static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1408
                                                gpointer data)
1409
{
1410
        folderview_update_item((FolderItem *)key, GPOINTER_TO_INT(data));
1411
}
1412

    
1413
void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1414
{
1415
        g_hash_table_foreach(table, folderview_update_item_foreach_func,
1416
                             GINT_TO_POINTER(update_summary));
1417
}
1418

    
1419
static gboolean folderview_update_all_updated_func(GNode *node, gpointer data)
1420
{
1421
        FolderItem *item;
1422

    
1423
        item = FOLDER_ITEM(node->data);
1424
        if (item->updated) {
1425
                debug_print("folderview_update_all_updated(): '%s' is updated\n", item->path);
1426
                folderview_update_item(item, GPOINTER_TO_INT(data));
1427
        }
1428

    
1429
        return FALSE;
1430
}
1431

    
1432
void folderview_update_all_updated(gboolean update_summary)
1433
{
1434
        GList *list;
1435
        Folder *folder;
1436

    
1437
        for (list = folder_get_list(); list != NULL; list = list->next) {
1438
                folder = (Folder *)list->data;
1439
                g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1440
                                folderview_update_all_updated_func,
1441
                                GINT_TO_POINTER(update_summary));
1442
        }
1443
}
1444

    
1445
static gboolean folderview_insert_item_recursive(FolderView *folderview,
1446
                                                 FolderItem *item,
1447
                                                 GtkTreeIter *iter)
1448
{
1449
        GNode *node;
1450
        GtkTreeIter iter_;
1451
        gboolean valid;
1452

    
1453
        g_return_val_if_fail(item != NULL, FALSE);
1454

    
1455
        valid = folderview_append_item(folderview, &iter_, item, FALSE);
1456
        g_return_val_if_fail(valid == TRUE, FALSE);
1457

    
1458
        for (node = item->node->children; node != NULL; node = node->next) {
1459
                FolderItem *child_item = FOLDER_ITEM(node->data);
1460
                folderview_insert_item_recursive(folderview, child_item, NULL);
1461
        }
1462

    
1463
        if (item->node->children && !item->collapsed) {
1464
                GtkTreePath *path;
1465

    
1466
                path = gtk_tree_model_get_path
1467
                        (GTK_TREE_MODEL(folderview->store), &iter_);
1468
                gtk_tree_view_expand_row(GTK_TREE_VIEW(folderview->treeview),
1469
                                         path, FALSE);
1470
                gtk_tree_path_free(path);
1471
        }
1472

    
1473
        if (iter)
1474
                *iter = iter_;
1475
        return TRUE;
1476
}
1477

    
1478
static void folderview_append_folder(FolderView *folderview, Folder *folder)
1479
{
1480
        g_return_if_fail(folder != NULL);
1481

    
1482
        folderview_insert_item_recursive
1483
                (folderview, FOLDER_ITEM(folder->node->data), NULL);
1484
}
1485

    
1486
void folderview_new_folder(FolderView *folderview)
1487
{
1488
        FolderItem *item;
1489

    
1490
        item = folderview_get_selected_item(folderview);
1491
        if (!item)
1492
                return;
1493

    
1494
        g_return_if_fail(item->folder != NULL);
1495

    
1496
        if (item->folder->klass->create_folder)
1497
                folderview_new_folder_cb(folderview, 0, NULL);
1498
        else if (FOLDER_TYPE(item->folder) == F_NEWS)
1499
                folderview_new_news_group_cb(folderview, 0, NULL);
1500
}
1501

    
1502
void folderview_rename_folder(FolderView *folderview)
1503
{
1504
        FolderItem *item;
1505

    
1506
        item = folderview_get_selected_item(folderview);
1507
        if (!item)
1508
                return;
1509

    
1510
        g_return_if_fail(item->folder != NULL);
1511

    
1512
        if (!item->path) return;
1513
        if (item->stype != F_NORMAL) return;
1514

    
1515
        if (item->folder->klass->rename_folder)
1516
                folderview_rename_folder_cb(folderview, 0, NULL);
1517
}
1518

    
1519
void folderview_move_folder(FolderView *folderview)
1520
{
1521
        FolderItem *item;
1522

    
1523
        item = folderview_get_selected_item(folderview);
1524
        if (!item)
1525
                return;
1526

    
1527
        g_return_if_fail(item->folder != NULL);
1528

    
1529
        if (!item->path) return;
1530
        if (item->stype != F_NORMAL) return;
1531

    
1532
        if (item->folder->klass->move_folder)
1533
                folderview_move_folder_cb(folderview, 0, NULL);
1534
}
1535

    
1536
void folderview_delete_folder(FolderView *folderview)
1537
{
1538
        FolderItem *item;
1539

    
1540
        item = folderview_get_selected_item(folderview);
1541
        if (!item)
1542
                return;
1543

    
1544
        g_return_if_fail(item->folder != NULL);
1545

    
1546
        if (!item->path) return;
1547
        if (item->stype != F_NORMAL) return;
1548

    
1549
        if (item->folder->klass->remove_folder)
1550
                folderview_delete_folder_cb(folderview, 0, NULL);
1551
        else if (FOLDER_TYPE(item->folder) == F_NEWS)
1552
                folderview_rm_news_group_cb(folderview, 0, NULL);
1553
}
1554

    
1555
void folderview_check_new_selected(FolderView *folderview)
1556
{
1557
        FolderItem *item;
1558

    
1559
        item = folderview_get_selected_item(folderview);
1560
        if (!item)
1561
                return;
1562

    
1563
        g_return_if_fail(item->folder != NULL);
1564
        if (item->parent != NULL) return;
1565

    
1566
        folderview_check_new(item->folder);
1567
}
1568

    
1569
void folderview_remove_mailbox(FolderView *folderview)
1570
{
1571
        FolderItem *item;
1572

    
1573
        item = folderview_get_selected_item(folderview);
1574
        if (!item)
1575
                return;
1576

    
1577
        g_return_if_fail(item->folder != NULL);
1578
        if (item->parent != NULL) return;
1579

    
1580
        switch (FOLDER_TYPE(item->folder)) {
1581
        case F_MH:
1582
        case F_MBOX:
1583
        case F_MAILDIR:
1584
                folderview_remove_mailbox_cb(folderview, 0, NULL);
1585
                break;
1586
        case F_IMAP:
1587
                folderview_rm_imap_server_cb(folderview, 0, NULL);
1588
                break;
1589
        case F_NEWS:
1590
                folderview_rm_news_server_cb(folderview, 0, NULL);
1591
                break;
1592
        default:
1593
                break;
1594
        }
1595
}
1596

    
1597
void folderview_rebuild_tree(FolderView *folderview)
1598
{
1599
        FolderItem *item;
1600

    
1601
        item = folderview_get_selected_item(folderview);
1602
        if (!item)
1603
                return;
1604

    
1605
        g_return_if_fail(item->folder != NULL);
1606
        if (item->parent != NULL) return;
1607

    
1608
        folderview_rescan_tree(folderview, item->folder);
1609
}
1610

    
1611
static gboolean folderview_menu_popup(FolderView *folderview,
1612
                                      GdkEventButton *event)
1613
{
1614
        FolderItem *item = NULL;
1615
        Folder *folder;
1616
        GtkWidget *popup;
1617
        GtkItemFactory *ifactory;
1618
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1619
        GtkTreeIter iter;
1620
        gboolean new_folder      = FALSE;
1621
        gboolean rename_folder   = FALSE;
1622
        gboolean move_folder     = FALSE;
1623
        gboolean delete_folder   = FALSE;
1624
        gboolean empty_trash     = FALSE;
1625
        gboolean download_msg    = FALSE;
1626
        gboolean update_tree     = FALSE;
1627
        gboolean update_summary  = FALSE;
1628
        gboolean mark_all_read   = FALSE;
1629
        gboolean send_queue      = FALSE;
1630
        gboolean rescan_tree     = FALSE;
1631
        gboolean remove_tree     = FALSE;
1632
        gboolean search_folder   = FALSE;
1633
        gboolean folder_property = FALSE;
1634

    
1635
        if (!event) return FALSE;
1636

    
1637
        if (event->button != 3)
1638
                return FALSE;
1639

    
1640
        if (!gtk_tree_selection_get_selected
1641
                (folderview->selection, NULL, &iter))
1642
                return FALSE;
1643

    
1644
        gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
1645
        g_return_val_if_fail(item != NULL, FALSE);
1646
        g_return_val_if_fail(item->folder != NULL, FALSE);
1647
        folder = item->folder;
1648

    
1649
        if (folderview->mainwin->lock_count == 0) {
1650
                new_folder = TRUE;
1651
                folder_property = TRUE;
1652
                search_folder = TRUE;
1653
                if (item->parent == NULL) {
1654
                        update_tree = remove_tree = TRUE;
1655
                } else {
1656
                        if (FOLDER_TYPE(folder) != F_IMAP)
1657
                                mark_all_read = TRUE;
1658
                        if (gtkut_tree_row_reference_equal
1659
                                (folderview->selected, folderview->opened)) {
1660
                                update_summary = TRUE;
1661
                                mark_all_read = TRUE;
1662
                        }
1663
                }
1664
                if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP) {
1665
                        if (item->parent == NULL)
1666
                                update_tree = rescan_tree = TRUE;
1667
                        else if (item->stype == F_NORMAL) {
1668
                                rename_folder = delete_folder = TRUE;
1669
                                if (folder->klass->move_folder)
1670
                                        move_folder = TRUE;
1671
                        } else if (item->stype == F_TRASH) {
1672
                                if (item->total > 0)
1673
                                        empty_trash = TRUE;
1674
                        } else if (item->stype == F_QUEUE) {
1675
                                if (item->total > 0)
1676
                                        send_queue = TRUE;
1677
                        }
1678
                } else if (FOLDER_TYPE(folder) == F_NEWS) {
1679
                        if (item->parent != NULL)
1680
                                delete_folder = TRUE;
1681
                }
1682
                if (item->stype == F_VIRTUAL) {
1683
                        new_folder = FALSE;
1684
                        rename_folder = delete_folder = TRUE;
1685
                }
1686
                if (FOLDER_TYPE(folder) == F_IMAP ||
1687
                    FOLDER_TYPE(folder) == F_NEWS) {
1688
                        if (item->no_select == FALSE &&
1689
                            item->stype != F_VIRTUAL)
1690
                                download_msg = TRUE;
1691
                }
1692
        } else {
1693
                search_folder = TRUE;
1694
                if (item->parent) {
1695
                        if (FOLDER_TYPE(folder) != F_IMAP)
1696
                                mark_all_read = TRUE;
1697
                        if (gtkut_tree_row_reference_equal
1698
                                (folderview->selected, folderview->opened)) {
1699
                                update_summary = TRUE;
1700
                                mark_all_read = TRUE;
1701
                        }
1702
                        if (item->stype == F_TRASH) {
1703
                                if (item->total > 0)
1704
                                        empty_trash = TRUE;
1705
                        }
1706
                }
1707
        }
1708

    
1709
#define SET_SENS(factory, name, sens)                                \
1710
{                                                                \
1711
        GtkWidget *widget;                                        \
1712
        widget = gtk_item_factory_get_item(factory, name);        \
1713
        if (widget)                                                \
1714
                gtk_widget_set_sensitive(widget, sens);                \
1715
}
1716

    
1717
#define SET_VISIBILITY(factory, name, visible)                        \
1718
{                                                                \
1719
        GtkWidget *widget;                                        \
1720
        widget = gtk_item_factory_get_item(factory, name);        \
1721
        if (widget) {                                                \
1722
                if (visible)                                        \
1723
                        gtk_widget_show(widget);                \
1724
                else                                                \
1725
                        gtk_widget_hide(widget);                \
1726
        }                                                        \
1727
}
1728

    
1729
        if (FOLDER_IS_LOCAL(folder)) {
1730
                popup = folderview->mail_popup;
1731
                ifactory = folderview->mail_factory;
1732
        } else if (FOLDER_TYPE(folder) == F_IMAP) {
1733
                popup = folderview->imap_popup;
1734
                ifactory = folderview->imap_factory;
1735
        } else if (FOLDER_TYPE(folder) == F_NEWS) {
1736
                popup = folderview->news_popup;
1737
                ifactory = folderview->news_factory;
1738
        } else
1739
                return FALSE;
1740

    
1741
        menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1742

    
1743
        SET_SENS(ifactory, "/Create new folder...", new_folder);
1744
        SET_SENS(ifactory, "/Rename folder...", rename_folder);
1745
        SET_SENS(ifactory, "/Move folder...", move_folder);
1746
        SET_SENS(ifactory, "/Delete folder", delete_folder);
1747
        SET_SENS(ifactory, "/Empty trash", empty_trash);
1748
        SET_SENS(ifactory, "/Download", download_msg);
1749
        SET_SENS(ifactory, "/Check for new messages", update_tree);
1750
        SET_SENS(ifactory, "/Rebuild folder tree", rescan_tree);
1751
        SET_SENS(ifactory, "/Update summary", update_summary);
1752
        SET_SENS(ifactory, "/Mark all read", mark_all_read);
1753
        SET_SENS(ifactory, "/Send queued messages", send_queue);
1754
        SET_SENS(ifactory, "/Search messages...", search_folder);
1755
        SET_SENS(ifactory, "/Edit search condition...", search_folder);
1756
        SET_SENS(ifactory, "/Properties...", folder_property);
1757

    
1758
        if (FOLDER_TYPE(folder) == F_NEWS) {
1759
                SET_SENS(ifactory, "/Subscribe to newsgroup...", new_folder);
1760
                SET_SENS(ifactory, "/Remove newsgroup", delete_folder);
1761
                SET_VISIBILITY(ifactory, "/Remove newsgroup",
1762
                               item->stype != F_VIRTUAL);
1763
                SET_VISIBILITY(ifactory, "/Rename folder...",
1764
                               item->stype == F_VIRTUAL);
1765
                SET_VISIBILITY(ifactory, "/Delete folder",
1766
                               item->stype == F_VIRTUAL);
1767
        }
1768

    
1769
        SET_VISIBILITY(ifactory, "/Mark all read", item->stype != F_QUEUE);
1770
        SET_VISIBILITY(ifactory, "/Send queued messages",
1771
                       item->stype == F_QUEUE);
1772
        SET_VISIBILITY(ifactory, "/Search messages...",
1773
                       item->stype != F_VIRTUAL);
1774
        SET_VISIBILITY(ifactory, "/Edit search condition...",
1775
                       item->stype == F_VIRTUAL);
1776

    
1777
#undef SET_SENS
1778
#undef SET_VISIBILITY
1779

    
1780
        syl_plugin_signal_emit("folderview-menu-popup", ifactory);
1781

    
1782
        gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1783
                       event->button, event->time);
1784

    
1785
        return FALSE;
1786
}
1787

    
1788

    
1789
/* callback functions */
1790

    
1791
static gboolean folderview_button_pressed(GtkWidget *widget,
1792
                                          GdkEventButton *event,
1793
                                          FolderView *folderview)
1794
{
1795
        GtkTreeView *treeview = GTK_TREE_VIEW(widget);
1796
        GtkTreePath *path;
1797

    
1798
        if (!event)
1799
                return FALSE;
1800

    
1801
        if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
1802
                                           &path, NULL, NULL, NULL))
1803
                return TRUE;
1804

    
1805
        if (folderview->selection_locked ||
1806
            summary_is_locked(folderview->summaryview))
1807
                return TRUE;
1808

    
1809
        if (event->button == 1 || event->button == 2) {
1810
                if (event->type == GDK_2BUTTON_PRESS) {
1811
                        if (gtk_tree_view_row_expanded(treeview, path))
1812
                                gtk_tree_view_collapse_row(treeview, path);
1813
                        else
1814
                                gtk_tree_view_expand_row(treeview, path, FALSE);
1815
                }
1816
                folderview->open_folder = TRUE;
1817
        } else if (event->button == 3) {
1818
                if (folderview->selected) {
1819
                        folderview->prev_selected =
1820
                                gtk_tree_row_reference_copy
1821
                                        (folderview->selected);
1822
                }
1823
                gtk_tree_selection_select_path(folderview->selection, path);
1824
                folderview_menu_popup(folderview, event);
1825
                gtk_tree_path_free(path);
1826
                return TRUE;
1827
        }
1828

    
1829
        gtk_tree_path_free(path);
1830
        return FALSE;
1831
}
1832

    
1833
static gboolean folderview_button_released(GtkWidget *treeview,
1834
                                           GdkEventButton *event,
1835
                                           FolderView *folderview)
1836
{
1837
        folderview->open_folder = FALSE;
1838
        return FALSE;
1839
}
1840

    
1841
static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1842
                                       FolderView *folderview)
1843
{
1844
        GtkTreePath *opened = NULL, *selected = NULL;
1845

    
1846
        if (!event) return FALSE;
1847

    
1848
        if (folderview->selection_locked ||
1849
            summary_is_locked(folderview->summaryview))
1850
                return TRUE;
1851

    
1852
        switch (event->keyval) {
1853
        case GDK_Return:
1854
        case GDK_KP_Enter:
1855
                if (folderview->selected) {
1856
                        folderview_select_row_ref(folderview,
1857
                                                  folderview->selected);
1858
                }
1859
                return TRUE;
1860
                break;
1861
        case GDK_space:
1862
        case GDK_KP_Space:
1863
                if (folderview->selected) {
1864
                        if (folderview->opened)
1865
                                opened = gtk_tree_row_reference_get_path
1866
                                        (folderview->opened);
1867
                        selected = gtk_tree_row_reference_get_path
1868
                                (folderview->selected);
1869
                        if (opened && selected &&
1870
                            gtk_tree_path_compare(opened, selected) == 0 &&
1871
                            (!folderview->summaryview->folder_item ||
1872
                             folderview->summaryview->folder_item->total == 0))
1873
                                folderview_select_next_unread(folderview);
1874
                        else
1875
                                folderview_select_row_ref(folderview,
1876
                                                          folderview->selected);
1877
                        gtk_tree_path_free(selected);
1878
                        gtk_tree_path_free(opened);
1879
                        return TRUE;
1880
                }
1881
                break;
1882
        default:
1883
                break;
1884
        }
1885

    
1886
        return FALSE;
1887
}
1888

    
1889
static gboolean folderview_focus_idle_func(gpointer data)
1890
{
1891
        FolderView *folderview = (FolderView *)data;
1892

    
1893
        GTK_WIDGET_SET_FLAGS(folderview->treeview, GTK_CAN_FOCUS);
1894

    
1895
        return FALSE;
1896
}
1897

    
1898
static void folderview_selection_changed(GtkTreeSelection *selection,
1899
                                         FolderView *folderview)
1900
{
1901
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1902
        FolderItem *item = NULL;
1903
        GtkTreeIter iter;
1904
        GtkTreePath *path;
1905
        gboolean opened;
1906

    
1907
        if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
1908
                if (folderview->selected) {
1909
                        gtk_tree_row_reference_free(folderview->selected);
1910
                        folderview->selected = NULL;
1911
                }
1912
                return;
1913
        }
1914

    
1915
        path = gtk_tree_model_get_path(model, &iter);
1916

    
1917
        gtk_tree_row_reference_free(folderview->selected);
1918
        folderview->selected = gtk_tree_row_reference_new(model, path);
1919

    
1920
        main_window_set_menu_sensitive(folderview->mainwin);
1921

    
1922
        if (!folderview->open_folder) {
1923
                gtk_tree_path_free(path);
1924
                return;
1925
        }
1926
        folderview->open_folder = FALSE;
1927

    
1928
        gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
1929
        if (!item) {
1930
                gtk_tree_path_free(path);
1931
                return;
1932
        }
1933

    
1934
        if (item->path)
1935
                debug_print(_("Folder %s is selected\n"), item->path);
1936

    
1937
        if (summary_is_locked(folderview->summaryview)) {
1938
                gtk_tree_path_free(path);
1939
                return;
1940
        }
1941

    
1942
        if (folderview->opened) {
1943
                GtkTreePath *open_path = NULL;
1944

    
1945
                open_path = gtk_tree_row_reference_get_path(folderview->opened);
1946
                if (open_path && gtk_tree_path_compare(open_path, path) == 0) {
1947
                        gtk_tree_path_free(open_path);
1948
                        gtk_tree_path_free(path);
1949
                        return;
1950
                }
1951
                gtk_tree_path_free(open_path);
1952
        }
1953

    
1954
        folderview->selection_locked = TRUE;
1955

    
1956
        GTK_EVENTS_FLUSH();
1957
        opened = summary_show(folderview->summaryview, item, FALSE);
1958

    
1959
        if (opened) {
1960
                gtk_tree_row_reference_free(folderview->opened);
1961
                folderview->opened = gtk_tree_row_reference_new(model, path);
1962
                gtk_tree_view_scroll_to_cell
1963
                        (GTK_TREE_VIEW(folderview->treeview), path, NULL, FALSE,
1964
                         0.0, 0.0);
1965
                if (item->total > 0) {
1966
                        /* don't let GtkTreeView::gtk_tree_view_button_press()
1967
                         * grab focus */
1968
                        GTK_WIDGET_UNSET_FLAGS(folderview->treeview,
1969
                                               GTK_CAN_FOCUS);
1970
                        g_idle_add(folderview_focus_idle_func, folderview);
1971
                }
1972
        } else
1973
                folderview_select_row_ref(folderview, folderview->opened);
1974

    
1975
        gtk_tree_path_free(path);
1976

    
1977
        folderview->selection_locked = FALSE;
1978
}
1979

    
1980
static void folderview_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter,
1981
                                    GtkTreePath *path, FolderView *folderview)
1982
{
1983
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1984
        FolderItem *item = NULL;
1985
        GtkTreeIter iter_;
1986
        gboolean valid;
1987

    
1988
        folderview->open_folder = FALSE;
1989

    
1990
        gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), iter,
1991
                           COL_FOLDER_ITEM, &item, -1);
1992
        g_return_if_fail(item != NULL);
1993
        item->collapsed = FALSE;
1994
        folderview_update_row(folderview, iter);
1995

    
1996
        valid = gtk_tree_model_iter_children(model, &iter_, iter);
1997

    
1998
        while (valid) {
1999
                FolderItem *child_item = NULL;
2000

    
2001
                gtk_tree_model_get(model, &iter_, COL_FOLDER_ITEM, &child_item,
2002
                                   -1);
2003
                if (child_item && child_item->node->children &&
2004
                    !child_item->collapsed) {
2005
                        GtkTreePath *path;
2006

    
2007
                        path = gtk_tree_model_get_path(model, &iter_);
2008
                        gtk_tree_view_expand_row
2009
                                (GTK_TREE_VIEW(folderview->treeview),
2010
                                 path, FALSE);
2011
                        gtk_tree_path_free(path);
2012
                }
2013
                valid = gtk_tree_model_iter_next(model, &iter_);
2014
        }
2015
}
2016

    
2017
static void folderview_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter,
2018
                                     GtkTreePath *path, FolderView *folderview)
2019
{
2020
        FolderItem *item = NULL;
2021

    
2022
        folderview->open_folder = FALSE;
2023

    
2024
        gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), iter,
2025
                           COL_FOLDER_ITEM, &item, -1);
2026
        g_return_if_fail(item != NULL);
2027
        item->collapsed = TRUE;
2028
        folderview_update_row(folderview, iter);
2029
}
2030

    
2031
static void folderview_popup_close(GtkMenuShell *menu_shell,
2032
                                   FolderView *folderview)
2033
{
2034
        GtkTreePath *path;
2035

    
2036
        if (!folderview->prev_selected) return;
2037

    
2038
        path = gtk_tree_row_reference_get_path(folderview->prev_selected);
2039
        gtk_tree_row_reference_free(folderview->prev_selected);
2040
        folderview->prev_selected = NULL;
2041
        if (!path)
2042
                return;
2043
        gtk_tree_selection_select_path(folderview->selection, path);
2044
        gtk_tree_path_free(path);
2045
}
2046

    
2047
static void folderview_col_resized(GtkWidget *widget, GtkAllocation *allocation,
2048
                                   FolderView *folderview)
2049
{
2050
        GtkTreeViewColumn *column;
2051
        gint type;
2052
        gint width = allocation->width;
2053

    
2054
        for (type = 0; type <= COL_TOTAL; type++) {
2055
                column = gtk_tree_view_get_column
2056
                        (GTK_TREE_VIEW(folderview->treeview), type);
2057
                if (column && column->button == widget) {
2058
                        switch (type) {
2059
                        case COL_FOLDER_NAME:
2060
                                prefs_common.folder_col_folder = width;
2061
                                break;
2062
                        case COL_NEW:
2063
                                prefs_common.folder_col_new = width;
2064
                                break;
2065
                        case COL_UNREAD:
2066
                                prefs_common.folder_col_unread = width;
2067
                                break;
2068
                        case COL_TOTAL:
2069
                                prefs_common.folder_col_total = width;
2070
                                break;
2071
                        default:
2072
                                break;
2073
                        }
2074
                        break;
2075
                }
2076
        }
2077
}
2078

    
2079
static void folderview_download_func(Folder *folder, FolderItem *item,
2080
                                     gpointer data)
2081
{
2082
        GList *list;
2083

    
2084
        for (list = folderview_list; list != NULL; list = list->next) {
2085
                FolderView *folderview = (FolderView *)list->data;
2086
                MainWindow *mainwin = folderview->mainwin;
2087
                gchar *str;
2088

    
2089
                str = g_strdup_printf
2090
                        (_("Downloading messages in %s ..."), item->path);
2091
                main_window_progress_set(mainwin,
2092
                                         GPOINTER_TO_INT(data), item->total);
2093
                STATUSBAR_PUSH(mainwin, str);
2094
                STATUSBAR_POP(mainwin);
2095
                g_free(str);
2096
        }
2097
}
2098

    
2099
static void folderview_download_cb(FolderView *folderview, guint action,
2100
                                   GtkWidget *widget)
2101
{
2102
        MainWindow *mainwin = folderview->mainwin;
2103
        FolderItem *item;
2104
        gint ret = 0;
2105

    
2106
        item = folderview_get_selected_item(folderview);
2107
        if (!item)
2108
                return;
2109
        if (item->stype == F_VIRTUAL)
2110
                return;
2111

    
2112
        g_return_if_fail(item->folder != NULL);
2113

    
2114
        if (item->parent == NULL) {
2115
                gchar *name, *msg;
2116

    
2117
                name = trim_string(item->name, 32);
2118
                msg = g_strdup_printf(_("Download all messages under '%s' ?"),
2119
                                      name);
2120
                g_free(name);
2121
                if (alertpanel(_("Download all messages"), msg,
2122
                               GTK_STOCK_YES, GTK_STOCK_NO, NULL)
2123
                    != G_ALERTDEFAULT) {
2124
                        g_free(msg);
2125
                        return;
2126
                }
2127
                g_free(msg);
2128
        }
2129

    
2130
        if (!main_window_toggle_online_if_offline(folderview->mainwin))
2131
                return;
2132

    
2133
        main_window_cursor_wait(mainwin);
2134
        inc_lock();
2135
        main_window_lock(mainwin);
2136
        gtk_widget_set_sensitive(folderview->treeview, FALSE);
2137
        main_window_progress_on(mainwin);
2138
        GTK_EVENTS_FLUSH();
2139
        folder_set_ui_func(item->folder, folderview_download_func, NULL);
2140

    
2141
        if (item->parent == NULL) {
2142
                GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2143
                GtkTreeIter iter;
2144
                gboolean valid;
2145
                FolderItem *cur_item;
2146

    
2147
                valid = gtkut_tree_model_find_by_column_data
2148
                        (model, &iter, NULL, COL_FOLDER_ITEM, item);
2149
                while ((valid = gtkut_tree_model_next(model, &iter)) == TRUE) {
2150
                        cur_item = NULL;
2151
                        gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM,
2152
                                           &cur_item, -1);
2153
                        if (!cur_item || cur_item->folder != item->folder)
2154
                                break;
2155
                        if (!cur_item->no_select &&
2156
                            cur_item->stype != F_VIRTUAL &&
2157
                            cur_item->stype != F_TRASH) {
2158
                                ret = folder_item_fetch_all_msg(cur_item);
2159
                                if (ret < 0)
2160
                                        break;
2161
                        }
2162
                }
2163
        } else
2164
                ret = folder_item_fetch_all_msg(item);
2165

    
2166
        if (ret < 0) {
2167
                gchar *name;
2168

    
2169
                name = trim_string(item->name, 32);
2170
                alertpanel_error(_("Error occurred while downloading messages in `%s'."), name);
2171
                g_free(name);
2172
        }
2173

    
2174
        folder_set_ui_func(item->folder, NULL, NULL);
2175
        main_window_progress_off(mainwin);
2176
        gtk_widget_set_sensitive(folderview->treeview, TRUE);
2177
        main_window_unlock(mainwin);
2178
        inc_unlock();
2179
        main_window_cursor_normal(mainwin);
2180
        statusbar_pop_all();
2181
}
2182

    
2183
static void folderview_update_tree_cb(FolderView *folderview, guint action,
2184
                                      GtkWidget *widget)
2185
{
2186
        FolderItem *item;
2187

    
2188
        item = folderview_get_selected_item(folderview);
2189
        if (!item)
2190
                return;
2191

    
2192
        g_return_if_fail(item->folder != NULL);
2193

    
2194
        if (action == 0)
2195
                folderview_check_new(item->folder);
2196
        else
2197
                folderview_rescan_tree(folderview, item->folder);
2198
}
2199

    
2200
static void folderview_update_summary_cb(FolderView *folderview, guint action,
2201
                                         GtkWidget *widget)
2202
{
2203
        if (!folderview->summaryview->folder_item)
2204
                return;
2205

    
2206
        GTK_EVENTS_FLUSH();
2207
        summary_show(folderview->summaryview,
2208
                     folderview->summaryview->folder_item, TRUE);
2209
}
2210

    
2211
static void folderview_mark_all_read_cb(FolderView *folderview, guint action,
2212
                                        GtkWidget *widget)
2213
{
2214
        FolderItem *item;
2215

    
2216
        item = folderview_get_selected_item(folderview);
2217
        if (!item)
2218
                return;
2219

    
2220
        if (item == folderview->summaryview->folder_item)
2221
                summary_mark_all_read(folderview->summaryview);
2222
        else {
2223
                procmsg_mark_all_read(item);
2224
                folderview_update_item(item, FALSE);
2225
                trayicon_set_tooltip(NULL);
2226
                trayicon_set_notify(FALSE);
2227
        }
2228
}
2229

    
2230
static void folderview_send_queue_cb(FolderView *folderview, guint action,
2231
                                     GtkWidget *widget)
2232
{
2233
        FolderItem *item;
2234
        gint ret;
2235

    
2236
        if (!main_window_toggle_online_if_offline(folderview->mainwin))
2237
                return;
2238

    
2239
        item = folderview_get_selected_item(folderview);
2240
        if (!item || item->stype != F_QUEUE)
2241
                return;
2242

    
2243
        ret = send_message_queue_all(item, prefs_common.savemsg,
2244
                                     prefs_common.filter_sent);
2245
        statusbar_pop_all();
2246
        if (ret > 0)
2247
                folder_item_scan(item);
2248

    
2249
        folderview_update_item(item, TRUE);
2250
        main_window_set_menu_sensitive(folderview->mainwin);
2251
        main_window_set_toolbar_sensitive(folderview->mainwin);
2252
}
2253

    
2254
static void folderview_new_folder_cb(FolderView *folderview, guint action,
2255
                                     GtkWidget *widget)
2256
{
2257
        FolderItem *item;
2258
        FolderItem *new_item;
2259
        gchar *new_folder;
2260
        gchar *name;
2261
        gchar *p;
2262

    
2263
        item = folderview_get_selected_item(folderview);
2264
        if (!item)
2265
                return;
2266

    
2267
        g_return_if_fail(item->folder != NULL);
2268

    
2269
        if (FOLDER_TYPE(item->folder) == F_IMAP)
2270
                g_return_if_fail(item->folder->account != NULL);
2271

    
2272
        if (FOLDER_TYPE(item->folder) == F_IMAP) {
2273
                new_folder = input_dialog
2274
                        (_("New folder"),
2275
                         _("Input the name of new folder:\n"
2276
                           "(if you want to create a folder to store subfolders,\n"
2277
                           " append `/' at the end of the name)"),
2278
                         _("NewFolder"));
2279
        } else {
2280
                new_folder = input_dialog(_("New folder"),
2281
                                          _("Input the name of new folder:"),
2282
                                          _("NewFolder"));
2283
        }
2284
        if (!new_folder) return;
2285
        AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
2286

    
2287
#ifdef G_OS_WIN32
2288
        p = strpbrk(new_folder, "\\/:*?\"<>|");
2289
        if ((p && FOLDER_TYPE(item->folder) != F_IMAP) || (p && *p != '/') ||
2290
            (p && p == '/' &&
2291
             FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
2292
                alertpanel_error(_("`%c' can't be included in folder name."),
2293
                                 *p);
2294
                return;
2295
        }
2296
#else
2297
        p = strchr(new_folder, G_DIR_SEPARATOR);
2298
        if ((p && FOLDER_TYPE(item->folder) != F_IMAP) ||
2299
            (p && FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
2300
                alertpanel_error(_("`%c' can't be included in folder name."),
2301
                                 G_DIR_SEPARATOR);
2302
                return;
2303
        }
2304
#endif
2305

    
2306
        name = trim_string(new_folder, 32);
2307
        AUTORELEASE_STR(name, {g_free(name); return;});
2308

    
2309
        /* find whether the directory already exists */
2310
        if (folder_find_child_item_by_name(item, new_folder)) {
2311
                alertpanel_error(_("The folder `%s' already exists."), name);
2312
                return;
2313
        }
2314

    
2315
        new_item = item->folder->klass->create_folder(item->folder, item,
2316
                                                      new_folder);
2317
        if (!new_item) {
2318
                alertpanel_error(_("Can't create the folder `%s'."), name);
2319
                return;
2320
        }
2321

    
2322
        folderview_append_item(folderview, NULL, new_item, TRUE);
2323
        folder_write_list();
2324
}
2325

    
2326
static void folderview_rename_folder_cb(FolderView *folderview, guint action,
2327
                                        GtkWidget *widget)
2328
{
2329
        FolderItem *item;
2330
        gchar *new_folder;
2331
        gchar *name;
2332
        gchar *message;
2333
        gchar *old_path;
2334
        gchar *old_id;
2335
        gchar *new_id;
2336
        GtkTreePath *sel_path;
2337
        GtkTreePath *open_path = NULL;
2338
        GtkTreeIter iter;
2339

    
2340
        item = folderview_get_selected_item(folderview);
2341
        if (!item)
2342
                return;
2343

    
2344
        g_return_if_fail(item->path != NULL);
2345
        g_return_if_fail(item->folder != NULL);
2346

    
2347
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2348

    
2349
        name = trim_string(item->name, 32);
2350
        message = g_strdup_printf(_("Input new name for `%s':"), name);
2351
        new_folder = input_dialog(_("Rename folder"), message,
2352
                                  g_basename(item->path));
2353
        g_free(message);
2354
        g_free(name);
2355
        if (!new_folder) {
2356
                gtk_tree_path_free(sel_path);
2357
                return;
2358
        }
2359
        AUTORELEASE_STR(new_folder, {g_free(new_folder); gtk_tree_path_free(sel_path); return;});
2360

    
2361
        if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
2362
                alertpanel_error(_("`%c' can't be included in folder name."),
2363
                                 G_DIR_SEPARATOR);
2364
                gtk_tree_path_free(sel_path);
2365
                return;
2366
        }
2367

    
2368
        if (folder_find_child_item_by_name(item->parent, new_folder)) {
2369
                name = trim_string(new_folder, 32);
2370
                alertpanel_error(_("The folder `%s' already exists."), name);
2371
                g_free(name);
2372
                gtk_tree_path_free(sel_path);
2373
                return;
2374
        }
2375

    
2376
        Xstrdup_a(old_path, item->path, {g_free(new_folder); return;});
2377
        old_id = folder_item_get_identifier(item);
2378

    
2379
        if (item->stype == F_VIRTUAL) {
2380
                if (virtual_get_class()->rename_folder(item->folder, item,
2381
                                                       new_folder) < 0) {
2382
                        alertpanel_error(_("Can't rename the folder '%s'."),
2383
                                         item->name);
2384
                        g_free(old_id);
2385
                        gtk_tree_path_free(sel_path);
2386
                        return;
2387
                }
2388
        } else if (item->folder->klass->rename_folder(item->folder, item,
2389
                                                      new_folder) < 0) {
2390
                alertpanel_error(_("Can't rename the folder '%s'."),
2391
                                 item->name);
2392
                g_free(old_id);
2393
                gtk_tree_path_free(sel_path);
2394
                return;
2395
        }
2396

    
2397
        if (folder_get_default_folder() == item->folder) {
2398
                filter_list_rename_path(old_path, item->path);
2399
                prefs_common_junk_folder_rename_path(old_path, item->path);
2400
        }
2401
        new_id = folder_item_get_identifier(item);
2402
        filter_list_rename_path(old_id, new_id);
2403
        prefs_common_junk_folder_rename_path(old_id, new_id);
2404
        g_free(old_id);
2405
        g_free(new_id);
2406

    
2407
        if (folderview->opened)
2408
                open_path = gtk_tree_row_reference_get_path(folderview->opened);
2409
        if (sel_path) {
2410
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2411
                                        &iter, sel_path);
2412
                folderview_update_row(folderview, &iter);
2413
        }
2414
        if (sel_path && open_path &&
2415
            (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2416
             gtk_tree_path_is_ancestor(sel_path, open_path))) {
2417
                GtkTreeRowReference *row;
2418

    
2419
                row = gtk_tree_row_reference_copy(folderview->opened);
2420
                folderview_unselect(folderview);
2421
                folderview_select_row_ref(folderview, row);
2422
                gtk_tree_row_reference_free(row);
2423
        }
2424
        gtk_tree_path_free(open_path);
2425
        gtk_tree_path_free(sel_path);
2426

    
2427
        folder_write_list();
2428
}
2429

    
2430
static void folderview_move_folder_cb(FolderView *folderview, guint action,
2431
                                      GtkWidget *widget)
2432
{
2433
        FolderItem *item;
2434
        FolderItem *new_parent;
2435
        GtkTreePath *sel_path;
2436
        GtkTreePath *open_path = NULL;
2437
        GtkTreeIter iter;
2438
        gchar *old_path, *old_id, *new_id;
2439

    
2440
        item = folderview_get_selected_item(folderview);
2441
        if (!item)
2442
                return;
2443

    
2444
        g_return_if_fail(item->path != NULL);
2445
        g_return_if_fail(item->folder != NULL);
2446

    
2447
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2448
        g_return_if_fail(sel_path != NULL);
2449

    
2450
        new_parent = foldersel_folder_sel(item->folder, FOLDER_SEL_MOVE_FOLDER,
2451
                                          NULL);
2452
        if (!new_parent || new_parent->folder != item->folder ||
2453
            new_parent == item->parent || new_parent->stype == F_VIRTUAL) {
2454
                gtk_tree_path_free(sel_path);
2455
                return;
2456
        }
2457

    
2458
        old_path = g_strdup(item->path);
2459
        old_id = folder_item_get_identifier(item);
2460

    
2461
        if (item->folder->klass->move_folder
2462
                (item->folder, item, new_parent) < 0) {
2463
                alertpanel_error(_("Can't move the folder `%s'."), item->name);
2464
                g_free(old_id);
2465
                g_free(old_path);
2466
                gtk_tree_path_free(sel_path);
2467
                return;
2468
        }
2469

    
2470
        if (folder_get_default_folder() == item->folder) {
2471
                filter_list_rename_path(old_path, item->path);
2472
                prefs_common_junk_folder_rename_path(old_path, item->path);
2473
        }
2474
        new_id = folder_item_get_identifier(item);
2475
        filter_list_rename_path(old_id, new_id);
2476
        prefs_common_junk_folder_rename_path(old_id, new_id);
2477
        g_free(new_id);
2478
        g_free(old_id);
2479
        g_free(old_path);
2480

    
2481
        if (folderview->opened)
2482
                open_path = gtk_tree_row_reference_get_path(folderview->opened);
2483
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
2484
                                sel_path);
2485
        if (sel_path && open_path &&
2486
            (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2487
             gtk_tree_path_is_ancestor(sel_path, open_path))) {
2488
                summary_clear_all(folderview->summaryview);
2489
                gtk_tree_row_reference_free(folderview->opened);
2490
                folderview->opened = NULL;
2491
        }
2492
        gtk_tree_path_free(open_path);
2493
        gtk_tree_path_free(sel_path);
2494

    
2495
        gtk_tree_store_remove(folderview->store, &iter);
2496
        if (folderview_insert_item_recursive(folderview, item, &iter)) {
2497
                gtkut_tree_view_expand_parent_all
2498
                        (GTK_TREE_VIEW(folderview->treeview), &iter);
2499
        }
2500

    
2501
        folder_write_list();
2502
}
2503

    
2504
static void folderview_delete_folder_cb(FolderView *folderview, guint action,
2505
                                        GtkWidget *widget)
2506
{
2507
        Folder *folder;
2508
        FolderItem *item;
2509
        gchar *message, *name;
2510
        AlertValue avalue;
2511
        gchar *old_path;
2512
        gchar *old_id;
2513
        GtkTreePath *sel_path, *open_path = NULL;
2514
        GtkTreeIter iter;
2515

    
2516
        item = folderview_get_selected_item(folderview);
2517
        if (!item)
2518
                return;
2519

    
2520
        g_return_if_fail(item->path != NULL);
2521
        g_return_if_fail(item->folder != NULL);
2522

    
2523
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2524
        g_return_if_fail(sel_path != NULL);
2525

    
2526
        folder = item->folder;
2527

    
2528
        name = trim_string(item->name, 32);
2529
        AUTORELEASE_STR(name, {g_free(name); gtk_tree_path_free(sel_path); return;});
2530
        if (item->stype == F_VIRTUAL) {
2531
                message = g_strdup_printf
2532
                        (_("Delete the search folder '%s' ?\n"
2533
                           "The real messages are not deleted."), name);
2534
                avalue = alertpanel_full(_("Delete search folder"), message,
2535
                                         ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2536
                                         GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2537
        } else {
2538
                message = g_strdup_printf
2539
                        (_("All folders and messages under '%s' will be permanently deleted.\n"
2540
                           "Recovery will not be possible.\n\n"
2541
                           "Do you really want to delete?"), name);
2542
                avalue = alertpanel_full(_("Delete folder"), message,
2543
                                         ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2544
                                         GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2545
        }
2546
        g_free(message);
2547
        if (avalue != G_ALERTDEFAULT) {
2548
                gtk_tree_path_free(sel_path);
2549
                return;
2550
        }
2551

    
2552
        Xstrdup_a(old_path, item->path, return);
2553
        old_id = folder_item_get_identifier(item);
2554

    
2555
        if (folderview->opened)
2556
                open_path = gtk_tree_row_reference_get_path(folderview->opened);
2557
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
2558
                                sel_path);
2559
        if (sel_path && open_path &&
2560
            (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2561
             gtk_tree_path_is_ancestor(sel_path, open_path))) {
2562
                summary_clear_all(folderview->summaryview);
2563
                gtk_tree_row_reference_free(folderview->opened);
2564
                folderview->opened = NULL;
2565
        }
2566
        gtk_tree_path_free(open_path);
2567
        gtk_tree_path_free(sel_path);
2568

    
2569
        if (item->stype == F_VIRTUAL) {
2570
                if (virtual_get_class()->remove_folder(folder, item) < 0) {
2571
                        alertpanel_error(_("Can't remove the folder '%s'."),
2572
                                         name);
2573
                        g_free(old_id);
2574
                        return;
2575
                }
2576
        } else if (folder->klass->remove_folder(folder, item) < 0) {
2577
                alertpanel_error(_("Can't remove the folder '%s'."), name);
2578
                g_free(old_id);
2579
                return;
2580
        }
2581

    
2582
        if (folder_get_default_folder() == folder)
2583
                filter_list_delete_path(old_path);
2584
        filter_list_delete_path(old_id);
2585
        g_free(old_id);
2586

    
2587
        gtk_tree_store_remove(folderview->store, &iter);
2588

    
2589
        folder_write_list();
2590
}
2591

    
2592
static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2593
                                      GtkWidget *widget)
2594
{
2595
        FolderItem *item;
2596
        Folder *folder;
2597
        GtkTreePath *sel_path, *open_path;
2598

    
2599
        item = folderview_get_selected_item(folderview);
2600
        if (!item)
2601
                return;
2602

    
2603
        g_return_if_fail(item->path != NULL);
2604
        g_return_if_fail(item->folder != NULL);
2605

    
2606
        folder = item->folder;
2607

    
2608
        if (folder->trash != item) return;
2609
        if (item->stype != F_TRASH) return;
2610

    
2611
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2612

    
2613
        if (alertpanel(_("Empty trash"),
2614
                       _("Delete all messages in the trash folder?"),
2615
                       GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT) {
2616
                gtk_tree_path_free(sel_path);
2617
                return;
2618
        }
2619

    
2620
        procmsg_empty_trash(folder->trash);
2621
        statusbar_pop_all();
2622
        folderview_update_item(folder->trash, TRUE);
2623
        trayicon_set_tooltip(NULL);
2624
        trayicon_set_notify(FALSE);
2625

    
2626
        open_path = gtk_tree_row_reference_get_path(folderview->opened);
2627
        if (open_path && sel_path &&
2628
            gtk_tree_path_compare(open_path, sel_path) == 0)
2629
                gtk_widget_grab_focus(folderview->treeview);
2630
        gtk_tree_path_free(open_path);
2631
        gtk_tree_path_free(sel_path);
2632
}
2633

    
2634
static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
2635
                                         GtkWidget *widget)
2636
{
2637
        FolderItem *item;
2638
        gchar *name;
2639
        gchar *message;
2640
        AlertValue avalue;
2641
        GtkTreePath *sel_path;
2642
        GtkTreeIter iter;
2643

    
2644
        item = folderview_get_selected_item(folderview);
2645
        if (!item)
2646
                return;
2647

    
2648
        g_return_if_fail(item->folder != NULL);
2649
        if (item->parent) return;
2650

    
2651
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2652

    
2653
        name = trim_string(item->folder->name, 32);
2654
        message = g_strdup_printf
2655
                (_("Really remove the mailbox `%s' ?\n"
2656
                   "(The messages are NOT deleted from the disk)"), name);
2657
        avalue = alertpanel_full(_("Remove mailbox"), message,
2658
                                 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2659
                                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2660
        g_free(message);
2661
        g_free(name);
2662
        if (avalue != G_ALERTDEFAULT) {
2663
                gtk_tree_path_free(sel_path);
2664
                return;
2665
        }
2666

    
2667
        if (folderview->summaryview->folder_item &&
2668
            folderview->summaryview->folder_item->folder == item->folder) {
2669
                summary_clear_all(folderview->summaryview);
2670
                gtk_tree_row_reference_free(folderview->opened);
2671
                folderview->opened = NULL;
2672
        }
2673
        folder_destroy(item->folder);
2674

    
2675
        if (sel_path) {
2676
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2677
                                        &iter, sel_path);
2678
                gtk_tree_path_free(sel_path);
2679
                gtk_tree_store_remove(folderview->store, &iter);
2680
        }
2681

    
2682
        folder_write_list();
2683
}
2684

    
2685
static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2686
                                         GtkWidget *widget)
2687
{
2688
        FolderItem *item;
2689
        PrefsAccount *account;
2690
        gchar *name;
2691
        gchar *message;
2692
        AlertValue avalue;
2693
        GtkTreePath *sel_path;
2694
        GtkTreeIter iter;
2695

    
2696
        item = folderview_get_selected_item(folderview);
2697
        if (!item)
2698
                return;
2699

    
2700
        g_return_if_fail(item->folder != NULL);
2701
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2702
        g_return_if_fail(item->folder->account != NULL);
2703

    
2704
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2705

    
2706
        name = trim_string(item->folder->name, 32);
2707
        message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"), name);
2708
        avalue = alertpanel_full(_("Delete IMAP4 account"), message,
2709
                                 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2710
                                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2711
        g_free(message);
2712
        g_free(name);
2713

    
2714
        if (avalue != G_ALERTDEFAULT) {
2715
                gtk_tree_path_free(sel_path);
2716
                return;
2717
        }
2718

    
2719
        if (folderview->summaryview->folder_item &&
2720
            folderview->summaryview->folder_item->folder == item->folder) {
2721
                summary_clear_all(folderview->summaryview);
2722
                gtk_tree_row_reference_free(folderview->opened);
2723
                folderview->opened = NULL;
2724
        }
2725

    
2726
        account = item->folder->account;
2727
        folder_destroy(item->folder);
2728
        account_destroy(account);
2729
        account_write_config_all();
2730

    
2731
        if (sel_path) {
2732
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2733
                                        &iter, sel_path);
2734
                gtk_tree_path_free(sel_path);
2735
                gtk_tree_store_remove(folderview->store, &iter);
2736
        }
2737

    
2738
        account_set_menu();
2739
        main_window_reflect_prefs_all();
2740
        folder_write_list();
2741
}
2742

    
2743
static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2744
                                         GtkWidget *widget)
2745
{
2746
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2747
        Folder *folder;
2748
        FolderItem *item;
2749
        FolderItem *rootitem = NULL;
2750
        FolderItem *newitem;
2751
        GSList *new_subscr;
2752
        GSList *cur;
2753
        GNode *gnode;
2754
        GtkTreePath *server_path;
2755
        GtkTreeIter iter, root;
2756

    
2757
        item = folderview_get_selected_item(folderview);
2758
        if (!item)
2759
                return;
2760

    
2761
        folder = item->folder;
2762
        g_return_if_fail(folder != NULL);
2763
        g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
2764
        g_return_if_fail(folder->account != NULL);
2765

    
2766
        server_path = gtk_tree_row_reference_get_path(folderview->selected);
2767
        g_return_if_fail(server_path != NULL);
2768
        gtk_tree_model_get_iter(model, &iter, server_path);
2769
        gtk_tree_path_free(server_path);
2770

    
2771
        if (!gtk_tree_model_iter_parent(model, &root, &iter))
2772
                root = iter;
2773

    
2774
        gtk_tree_model_get(model, &root, COL_FOLDER_ITEM, &rootitem, -1);
2775

    
2776
        new_subscr = subscribe_dialog(folder);
2777

    
2778
        /* remove unsubscribed newsgroups */
2779
        for (gnode = folder->node->children; gnode != NULL; ) {
2780
                GNode *next = gnode->next;
2781
                GtkTreeIter found;
2782

    
2783
                item = FOLDER_ITEM(gnode->data);
2784
                if (g_slist_find_custom(new_subscr, item->path,
2785
                                        (GCompareFunc)g_ascii_strcasecmp)
2786
                    != NULL) {
2787
                        gnode = next;
2788
                        continue;
2789
                }
2790

    
2791
                if (!gtkut_tree_model_find_by_column_data
2792
                        (model, &found, &root, COL_FOLDER_ITEM, item)) {
2793
                        gnode = next;
2794
                        continue;
2795
                }
2796

    
2797
                if (folderview->summaryview->folder_item == item) {
2798
                        summary_clear_all(folderview->summaryview);
2799
                        gtk_tree_row_reference_free(folderview->opened);
2800
                        folderview->opened = NULL;
2801
                }
2802

    
2803
                folder_item_remove(item);
2804
                gtk_tree_store_remove(folderview->store, &found);
2805

    
2806
                gnode = next;
2807
        }
2808

    
2809
        /* add subscribed newsgroups */
2810
        for (cur = new_subscr; cur != NULL; cur = cur->next) {
2811
                gchar *name = (gchar *)cur->data;
2812

    
2813
                if (folder_find_child_item_by_name(rootitem, name) != NULL)
2814
                        continue;
2815

    
2816
                newitem = folder_item_new(name, name);
2817
                folder_item_append(rootitem, newitem);
2818
                folderview_append_item(folderview, NULL, newitem, TRUE);
2819
        }
2820

    
2821
        if (new_subscr) {
2822
                server_path = gtk_tree_model_get_path(model, &root);
2823
                gtk_tree_view_expand_row(GTK_TREE_VIEW(folderview->treeview),
2824
                                         server_path, FALSE);
2825
                gtk_tree_path_free(server_path);
2826
        }
2827

    
2828
        slist_free_strings(new_subscr);
2829
        g_slist_free(new_subscr);
2830

    
2831
        folder_write_list();
2832
}
2833

    
2834
static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2835
                                        GtkWidget *widget)
2836
{
2837
        FolderItem *item;
2838
        gchar *name;
2839
        gchar *message;
2840
        AlertValue avalue;
2841
        GtkTreePath *sel_path, *open_path = NULL;
2842
        GtkTreeIter iter;
2843

    
2844
        item = folderview_get_selected_item(folderview);
2845
        if (!item)
2846
                return;
2847

    
2848
        if (item->stype == F_VIRTUAL) {
2849
                folderview_delete_folder_cb(folderview, 0, widget);
2850
                return;
2851
        }
2852

    
2853
        g_return_if_fail(item->folder != NULL);
2854
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2855
        g_return_if_fail(item->folder->account != NULL);
2856

    
2857
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2858
        g_return_if_fail(sel_path != NULL);
2859

    
2860
        name = trim_string_before(item->path, 32);
2861
        message = g_strdup_printf(_("Really delete newsgroup `%s'?"), name);
2862
        avalue = alertpanel_full(_("Delete newsgroup"), message,
2863
                                 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2864
                                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2865
        g_free(message);
2866
        g_free(name);
2867
        if (avalue != G_ALERTDEFAULT) {
2868
                gtk_tree_path_free(sel_path);
2869
                return;
2870
        }
2871

    
2872
        if (folderview->opened)
2873
                open_path = gtk_tree_row_reference_get_path(folderview->opened);
2874
        gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
2875
                                sel_path);
2876
        if (open_path && sel_path &&
2877
            gtk_tree_path_compare(open_path, sel_path) == 0) {
2878
                summary_clear_all(folderview->summaryview);
2879
                gtk_tree_row_reference_free(folderview->opened);
2880
                folderview->opened = NULL;
2881
        }
2882
        gtk_tree_path_free(open_path);
2883
        gtk_tree_path_free(sel_path);
2884

    
2885
        folder_item_remove(item);
2886
        gtk_tree_store_remove(folderview->store, &iter);
2887
        folder_write_list();
2888
}
2889

    
2890
static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2891
                                         GtkWidget *widget)
2892
{
2893
        FolderItem *item;
2894
        PrefsAccount *account;
2895
        gchar *name;
2896
        gchar *message;
2897
        AlertValue avalue;
2898
        GtkTreePath *sel_path;
2899
        GtkTreeIter iter;
2900

    
2901
        item = folderview_get_selected_item(folderview);
2902
        if (!item)
2903
                return;
2904

    
2905
        g_return_if_fail(item->folder != NULL);
2906
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2907
        g_return_if_fail(item->folder->account != NULL);
2908

    
2909
        sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2910

    
2911
        name = trim_string(item->folder->name, 32);
2912
        message = g_strdup_printf(_("Really delete news account `%s'?"), name);
2913
        avalue = alertpanel_full(_("Delete news account"), message,
2914
                                 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2915
                                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2916
        g_free(message);
2917
        g_free(name);
2918

    
2919
        if (avalue != G_ALERTDEFAULT) {
2920
                gtk_tree_path_free(sel_path);
2921
                return;
2922
        }
2923

    
2924
        if (folderview->summaryview->folder_item &&
2925
            folderview->summaryview->folder_item->folder == item->folder) {
2926
                summary_clear_all(folderview->summaryview);
2927
                gtk_tree_row_reference_free(folderview->opened);
2928
                folderview->opened = NULL;
2929
        }
2930

    
2931
        account = item->folder->account;
2932
        folder_destroy(item->folder);
2933
        account_destroy(account);
2934
        account_write_config_all();
2935

    
2936
        if (sel_path) {
2937
                gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2938
                                        &iter, sel_path);
2939
                gtk_tree_path_free(sel_path);
2940
                gtk_tree_store_remove(folderview->store, &iter);
2941
        }
2942

    
2943
        account_set_menu();
2944
        main_window_reflect_prefs_all();
2945
        folder_write_list();
2946
}
2947

    
2948
static void folderview_search_cb(FolderView *folderview, guint action,
2949
                                 GtkWidget *widget)
2950
{
2951
        FolderItem *item;
2952

    
2953
        item = folderview_get_selected_item(folderview);
2954
        if (!item)
2955
                return;
2956

    
2957
        if (item->stype == F_VIRTUAL) {
2958
                GtkTreePath *sel_path, *open_path;
2959

    
2960
                sel_path = gtk_tree_row_reference_get_path
2961
                        (folderview->selected);
2962
                open_path = gtk_tree_row_reference_get_path(folderview->opened);
2963

    
2964
                if (prefs_search_folder_open(item)) {
2965
                        if (sel_path && open_path &&
2966
                            gtk_tree_path_compare(open_path, sel_path) == 0) {
2967
                                GtkTreeRowReference *row;
2968
                                row = gtk_tree_row_reference_copy(folderview->opened);
2969
                                folderview_unselect(folderview);
2970
                                summary_clear_all(folderview->summaryview);
2971
                                folderview_select_row_ref(folderview, row);
2972
                                gtk_tree_row_reference_free(row);
2973
                        }
2974
                }
2975

    
2976
                gtk_tree_path_free(open_path);
2977
                gtk_tree_path_free(sel_path);
2978
        } else
2979
                query_search(item);
2980
}
2981

    
2982
static void folderview_property_cb(FolderView *folderview, guint action,
2983
                                   GtkWidget *widget)
2984
{
2985
        FolderItem *item;
2986

    
2987
        item = folderview_get_selected_item(folderview);
2988
        if (!item)
2989
                return;
2990

    
2991
        g_return_if_fail(item->folder != NULL);
2992

    
2993
        if (item->parent == NULL && item->folder->account)
2994
                account_open(item->folder->account);
2995
        else
2996
                prefs_folder_item_open(item);
2997
}
2998

    
2999
static gint auto_expand_timeout(gpointer data)
3000
{
3001
        FolderView *folderview = data;
3002
        GtkTreeView *treeview = GTK_TREE_VIEW(folderview->treeview);
3003
        GtkTreePath *path = NULL;
3004

    
3005
        gtk_tree_view_get_drag_dest_row(treeview, &path, NULL);
3006

    
3007
        if (path) {
3008
                gtk_tree_view_expand_row(treeview, path, FALSE);
3009
                gtk_tree_path_free(path);
3010
                folderview->expand_timeout = 0;
3011

    
3012
                return FALSE;
3013
        } else
3014
                return TRUE;
3015
}
3016

    
3017
static void remove_auto_expand_timeout(FolderView *folderview)
3018
{
3019
        if (folderview->expand_timeout != 0) {
3020
                g_source_remove(folderview->expand_timeout);
3021
                folderview->expand_timeout = 0;
3022
        }
3023
}
3024

    
3025
static gint auto_scroll_timeout(gpointer data)
3026
{
3027
        FolderView *folderview = data;
3028

    
3029
        gtkut_tree_view_vertical_autoscroll
3030
                (GTK_TREE_VIEW(folderview->treeview));
3031

    
3032
        return TRUE;
3033
}
3034

    
3035
static void remove_auto_scroll_timeout(FolderView *folderview)
3036
{
3037
        if (folderview->scroll_timeout != 0) {
3038
                g_source_remove(folderview->scroll_timeout);
3039
                folderview->scroll_timeout = 0;
3040
        }
3041
}
3042

    
3043
static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
3044
                                          GdkDragContext *context,
3045
                                          gint            x,
3046
                                          gint            y,
3047
                                          guint           time,
3048
                                          FolderView     *folderview)
3049
{
3050
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
3051
        GtkTreePath *path = NULL, *prev_path = NULL;
3052
        GtkTreeIter iter;
3053
        FolderItem *item = NULL, *src_item = NULL;
3054
        gboolean acceptable = FALSE;
3055

    
3056
        if (gtk_tree_view_get_dest_row_at_pos
3057
                (GTK_TREE_VIEW(widget), x, y, &path, NULL)) {
3058
                gtk_tree_model_get_iter(model, &iter, path);
3059
                gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
3060
                src_item = folderview->summaryview->folder_item;
3061
                if (src_item && src_item != item &&
3062
                    src_item->stype != F_QUEUE && item->stype != F_QUEUE &&
3063
                    item->stype != F_VIRTUAL)
3064
                        acceptable = FOLDER_ITEM_CAN_ADD(item);
3065
        } else
3066
                remove_auto_expand_timeout(folderview);
3067

    
3068
        gtk_tree_view_get_drag_dest_row(GTK_TREE_VIEW(widget),
3069
                                        &prev_path, NULL);
3070
        if (!path || (prev_path && gtk_tree_path_compare(path, prev_path) != 0))
3071
                remove_auto_expand_timeout(folderview);
3072
        if (prev_path)
3073
                gtk_tree_path_free(prev_path);
3074

    
3075
        gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), path,
3076
                                        GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
3077

    
3078
        if (path) {
3079
                if (folderview->expand_timeout == 0) {
3080
                        folderview->expand_timeout =
3081
                                g_timeout_add(1000, auto_expand_timeout,
3082
                                              folderview);
3083
                } else if (folderview->scroll_timeout == 0) {
3084
                        folderview->scroll_timeout =
3085
                                g_timeout_add(150, auto_scroll_timeout,
3086
                                              folderview);
3087
                }
3088
        }
3089

    
3090
#ifdef G_OS_WIN32
3091
        /* Win32 hack: somehow context->actions is not properly set on Win32 */
3092
        {
3093
                GdkWindow *rootwin;
3094
                GdkModifierType state;
3095

    
3096
                rootwin = gtk_widget_get_root_window(widget);
3097
                gdk_window_get_pointer(rootwin, NULL, NULL, &state);
3098
                if ((state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) == 0)
3099
                        context->actions = GDK_ACTION_MOVE | GDK_ACTION_COPY;
3100
        }
3101
#endif
3102

    
3103
        if (acceptable) {
3104
                if ((context->actions & GDK_ACTION_MOVE) != 0 &&
3105
                    FOLDER_ITEM_CAN_ADD(src_item))
3106
                        gdk_drag_status(context, GDK_ACTION_MOVE, time);
3107
                else if ((context->actions & GDK_ACTION_COPY) != 0)
3108
                        gdk_drag_status(context, GDK_ACTION_COPY, time);
3109
                else if ((context->actions & GDK_ACTION_LINK) != 0)
3110
                        gdk_drag_status(context, GDK_ACTION_LINK, time);
3111
                else
3112
                        gdk_drag_status(context, 0, time);
3113
        } else
3114
                gdk_drag_status(context, 0, time);
3115

    
3116
        if (path)
3117
                gtk_tree_path_free(path);
3118

    
3119
        return TRUE;
3120
}
3121

    
3122
static void folderview_drag_leave_cb(GtkWidget      *widget,
3123
                                     GdkDragContext *context,
3124
                                     guint           time,
3125
                                     FolderView     *folderview)
3126
{
3127
        remove_auto_expand_timeout(folderview);
3128
        remove_auto_scroll_timeout(folderview);
3129

    
3130
        gtk_tree_view_set_drag_dest_row
3131
                (GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
3132
}
3133

    
3134
static void folderview_drag_received_cb(GtkWidget        *widget,
3135
                                        GdkDragContext   *context,
3136
                                        gint              x,
3137
                                        gint              y,
3138
                                        GtkSelectionData *data,
3139
                                        guint             info,
3140
                                        guint             time,
3141
                                        FolderView       *folderview)
3142
{
3143
        GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
3144
        GtkTreePath *path = NULL;
3145
        GtkTreeIter iter;
3146
        FolderItem *item = NULL, *src_item;
3147

    
3148
        remove_auto_expand_timeout(folderview);
3149
        remove_auto_scroll_timeout(folderview);
3150

    
3151
        if (!gtk_tree_view_get_dest_row_at_pos
3152
                (GTK_TREE_VIEW(widget), x, y, &path, NULL))
3153
                return;
3154

    
3155
        gtk_tree_model_get_iter(model, &iter, path);
3156
        gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
3157
        src_item = folderview->summaryview->folder_item;
3158

    
3159
        if (FOLDER_ITEM_CAN_ADD(item) && src_item && src_item != item &&
3160
            src_item->stype != F_QUEUE && item->stype != F_QUEUE &&
3161
            item->stype != F_VIRTUAL) {
3162
                if ((context->actions & GDK_ACTION_MOVE) != 0 &&
3163
                    FOLDER_ITEM_CAN_ADD(src_item)) {
3164
                        summary_move_selected_to(folderview->summaryview, item);
3165
                        context->action = 0;
3166
                        gtk_drag_finish(context, TRUE, FALSE, time);
3167
                } else if ((context->actions & GDK_ACTION_COPY) != 0) {
3168
                        summary_copy_selected_to(folderview->summaryview, item);
3169
                        gtk_drag_finish(context, TRUE, FALSE, time);
3170
                } else
3171
                        gtk_drag_finish(context, FALSE, FALSE, time);
3172
        } else
3173
                gtk_drag_finish(context, FALSE, FALSE, time);
3174

    
3175
        gtk_tree_path_free(path);
3176
}
3177

    
3178
static gint folderview_folder_name_compare(GtkTreeModel *model,
3179
                                           GtkTreeIter *a, GtkTreeIter *b,
3180
                                           gpointer data)
3181
{
3182
        FolderItem *item_a = NULL, *item_b = NULL;
3183

    
3184
        gtk_tree_model_get(model, a, COL_FOLDER_ITEM, &item_a, -1);
3185
        gtk_tree_model_get(model, b, COL_FOLDER_ITEM, &item_b, -1);
3186

    
3187
        return folder_item_compare(item_a, item_b);
3188
}