719a4bdc3838eb19b562e4600cb10347eb97766b
[claws.git] / src / folderview.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2004 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 <gdk/gdkkeysyms.h>
24 #include <gtk/gtkwidget.h>
25 #include <gtk/gtkscrolledwindow.h>
26 #include <gtk/gtkctree.h>
27 #include <gtk/gtkcontainer.h>
28 #include <gtk/gtkclist.h>
29 #include <gtk/gtkstyle.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkmain.h>
32 #include <gtk/gtkstatusbar.h>
33 #include <gtk/gtkmenu.h>
34 #include <gtk/gtkmenuitem.h>
35 #include <gtk/gtkitemfactory.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39
40 #include "intl.h"
41 #include "main.h"
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
49 #include "menu.h"
50 #include "stock_pixmap.h"
51 #include "procmsg.h"
52 #include "utils.h"
53 #include "gtkutils.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
58 #include "account.h"
59 #include "folder.h"
60 #include "foldersel.h"
61 #include "inc.h"
62 #include "statusbar.h"
63 #include "hooks.h"
64 #include "folderutils.h"
65
66 typedef enum
67 {
68         COL_FOLDER      = 0,
69         COL_NEW         = 1,
70         COL_UNREAD      = 2,
71         COL_TOTAL       = 3
72 } FolderColumnPos;
73
74 #define N_FOLDER_COLS           4
75 #define COL_FOLDER_WIDTH        150
76 #define COL_NUM_WIDTH           32
77
78 static GList *folderview_list = NULL;
79
80 static GtkStyle *normal_style;
81 static GtkStyle *normal_color_style;
82 static GtkStyle *bold_style;
83 static GtkStyle *bold_color_style;
84 static GtkStyle *bold_tgtfold_style;
85
86 static GdkBitmap *inboxxpm;
87 static GdkBitmap *inboxxpmmask;
88 static GdkPixmap *inboxhrmxpm;
89 static GdkBitmap *inboxhrmxpmmask;
90 static GdkPixmap *inboxopenxpm;
91 static GdkBitmap *inboxopenxpmmask;
92 static GdkPixmap *inboxopenhrmxpm;
93 static GdkBitmap *inboxopenhrmxpmmask;
94 static GdkPixmap *outboxxpm;
95 static GdkBitmap *outboxxpmmask;
96 static GdkPixmap *outboxhrmxpm;
97 static GdkBitmap *outboxhrmxpmmask;
98 static GdkPixmap *outboxopenxpm;
99 static GdkBitmap *outboxopenxpmmask;
100 static GdkPixmap *outboxopenhrmxpm;
101 static GdkBitmap *outboxopenhrmxpmmask;
102 static GdkPixmap *folderxpm;
103 static GdkBitmap *folderxpmmask;
104 static GdkPixmap *folderhrmxpm;
105 static GdkBitmap *folderhrmxpmmask;
106 static GdkPixmap *folderopenxpm;
107 static GdkBitmap *folderopenxpmmask;
108 static GdkPixmap *folderopenhrmxpm;
109 static GdkBitmap *folderopenhrmxpmmask;
110 static GdkPixmap *trashopenxpm;
111 static GdkBitmap *trashopenxpmmask;
112 static GdkPixmap *trashopenhrmxpm;
113 static GdkBitmap *trashopenhrmxpmmask;
114 static GdkPixmap *trashxpm;
115 static GdkBitmap *trashxpmmask;
116 static GdkPixmap *trashhrmxpm;
117 static GdkBitmap *trashhrmxpmmask;
118 static GdkPixmap *queuexpm;
119 static GdkBitmap *queuexpmmask;
120 static GdkPixmap *queuehrmxpm;
121 static GdkBitmap *queuehrmxpmmask;
122 static GdkPixmap *queueopenxpm;
123 static GdkBitmap *queueopenxpmmask;
124 static GdkPixmap *queueopenhrmxpm;
125 static GdkBitmap *queueopenhrmxpmmask;
126 static GdkPixmap *newxpm;
127 static GdkBitmap *newxpmmask;
128 static GdkPixmap *unreadxpm;
129 static GdkBitmap *unreadxpmmask;
130 static GdkPixmap *draftsxpm;
131 static GdkBitmap *draftsxpmmask;
132 static GdkPixmap *draftsopenxpm;
133 static GdkBitmap *draftsopenxpmmask;
134
135 static void folderview_select_node       (FolderView    *folderview,
136                                           GtkCTreeNode  *node);
137 static void folderview_set_folders       (FolderView    *folderview);
138 static void folderview_sort_folders      (FolderView    *folderview,
139                                           GtkCTreeNode  *root,
140                                           Folder        *folder);
141 static void folderview_append_folder     (FolderView    *folderview,
142                                           Folder        *folder);
143 static void folderview_update_node       (FolderView    *folderview,
144                                           GtkCTreeNode  *node);
145
146 static gint folderview_clist_compare    (GtkCList       *clist,
147                                          gconstpointer   ptr1,
148                                          gconstpointer   ptr2);
149
150 /* callback functions */
151 static void folderview_button_pressed   (GtkWidget      *ctree,
152                                          GdkEventButton *event,
153                                          FolderView     *folderview);
154 static void folderview_button_released  (GtkWidget      *ctree,
155                                          GdkEventButton *event,
156                                          FolderView     *folderview);
157 static void folderview_key_pressed      (GtkWidget      *widget,
158                                          GdkEventKey    *event,
159                                          FolderView     *folderview);
160 static void folderview_selected         (GtkCTree       *ctree,
161                                          GtkCTreeNode   *row,
162                                          gint            column,
163                                          FolderView     *folderview);
164 static void folderview_tree_expanded    (GtkCTree       *ctree,
165                                          GtkCTreeNode   *node,
166                                          FolderView     *folderview);
167 static void folderview_tree_collapsed   (GtkCTree       *ctree,
168                                          GtkCTreeNode   *node,
169                                          FolderView     *folderview);
170 static void folderview_popup_close      (GtkMenuShell   *menu_shell,
171                                          FolderView     *folderview);
172 static void folderview_col_resized      (GtkCList       *clist,
173                                          gint            column,
174                                          gint            width,
175                                          FolderView     *folderview);
176
177 static void mark_all_read_cb            (FolderView    *folderview,
178                                          guint           action,
179                                          GtkWidget      *widget);
180
181 static void folderview_search_cb        (FolderView     *folderview,
182                                          guint           action,
183                                          GtkWidget      *widget);
184
185 static void folderview_property_cb      (FolderView     *folderview,
186                                          guint           action,
187                                          GtkWidget      *widget);
188
189 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
190                                           GdkDragContext *context,
191                                           gint            x,
192                                           gint            y,
193                                           guint           time,
194                                           FolderView     *folderview);
195 static void folderview_drag_leave_cb     (GtkWidget        *widget,
196                                           GdkDragContext   *context,
197                                           guint             time,
198                                           FolderView       *folderview);
199 static void folderview_drag_received_cb  (GtkWidget        *widget,
200                                           GdkDragContext   *drag_context,
201                                           gint              x,
202                                           gint              y,
203                                           GtkSelectionData *data,
204                                           guint             info,
205                                           guint             time,
206                                           FolderView       *folderview);
207 static void folderview_start_drag        (GtkWidget *widget, gint button, GdkEvent *event,
208                                           FolderView       *folderview);
209 static void folderview_drag_data_get     (GtkWidget        *widget,
210                                           GdkDragContext   *drag_context,
211                                           GtkSelectionData *selection_data,
212                                           guint             info,
213                                           guint             time,
214                                           FolderView       *folderview);
215 static void folderview_drag_end_cb       (GtkWidget        *widget,
216                                           GdkDragContext   *drag_context,
217                                           FolderView       *folderview);
218
219 void folderview_create_folder_node       (FolderView       *folderview, 
220                                           FolderItem       *item);
221 gboolean folderview_update_folder        (gpointer          source,
222                                           gpointer          userdata);
223 gboolean folderview_update_item_claws    (gpointer          source,
224                                           gpointer          data);
225 static void folderview_processing_cb(FolderView *folderview, guint action,
226                                      GtkWidget *widget);
227
228 GHashTable *folderview_popups;
229
230 static GtkItemFactoryEntry folderview_common_popup_entries[] =
231 {
232         {N_("/Mark all _read"),         NULL, mark_all_read_cb, 0, NULL},
233         {N_("/_Search folder..."),      NULL, folderview_search_cb, 0, NULL},
234         {N_("/_Properties..."),         NULL, folderview_property_cb, 0, NULL},
235         {N_("/_Processing..."),         NULL, folderview_processing_cb, 0, NULL},
236 };
237
238 GtkTargetEntry folderview_drag_types[] =
239 {
240         {"text/plain", GTK_TARGET_SAME_APP, TARGET_DUMMY}
241 };
242
243 void folderview_initialize(void)
244 {
245         FolderViewPopup *fpopup;
246         guint i, n_entries;
247         GSList *entries = NULL;
248
249         fpopup = g_new0(FolderViewPopup, 1);
250
251         n_entries = sizeof(folderview_common_popup_entries) /
252                 sizeof(folderview_common_popup_entries[0]);
253         for (i = 0; i < n_entries; i++)
254                 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
255
256         fpopup->klass = "common";
257         fpopup->path = "<CommonFolder>";
258         fpopup->entries = entries;
259         fpopup->set_sensitivity = NULL;
260
261         folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
262         g_hash_table_insert(folderview_popups, "common", fpopup);
263 }
264
265 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
266 {
267         GSList *entries;
268         GtkItemFactory *factory;
269         FolderViewPopup *fpopup_common;
270         GtkWidget *popup;
271
272         factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
273         gtk_item_factory_set_translate_func(factory, menu_translate,
274                                             NULL, NULL);
275
276         for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
277                 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
278
279         fpopup_common = g_hash_table_lookup(folderview_popups, "common");
280         if (fpopup_common != fpopup)
281                 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
282                         gtk_item_factory_create_item(factory, entries->data, folderview, 1);
283
284         popup = gtk_item_factory_get_widget(factory, fpopup->path);
285         gtk_signal_connect(GTK_OBJECT(popup), "selection_done",
286                            GTK_SIGNAL_FUNC(folderview_popup_close),
287                            folderview);
288
289         return factory;
290 }
291
292 static void create_ifactories(gpointer key, gpointer value, gpointer data)
293 {
294         FolderView *folderview = data;
295         FolderViewPopup *fpopup = value;
296         GtkItemFactory *factory;
297
298         factory = create_ifactory(folderview, fpopup);
299         g_hash_table_insert(folderview->popups, fpopup->klass, factory);
300 }
301
302 FolderView *folderview_create(void)
303 {
304         FolderView *folderview;
305         GtkWidget *scrolledwin;
306         GtkWidget *ctree;
307         gchar *titles[N_FOLDER_COLS];
308         gint i;
309
310         debug_print("Creating folder view...\n");
311         folderview = g_new0(FolderView, 1);
312
313         titles[COL_FOLDER] = _("Folder");
314         titles[COL_NEW]    = _("New");
315         titles[COL_UNREAD] = _("Unread");
316         titles[COL_TOTAL]  = _("#");
317
318         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
319         gtk_scrolled_window_set_policy
320                 (GTK_SCROLLED_WINDOW(scrolledwin),
321                  GTK_POLICY_AUTOMATIC,
322                  prefs_common.folderview_vscrollbar_policy);
323         gtk_widget_set_usize(scrolledwin,
324                              prefs_common.folderview_width,
325                              prefs_common.folderview_height);
326
327         ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, COL_FOLDER, titles);
328         
329         gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
330         gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
331         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_NEW,
332                                            GTK_JUSTIFY_RIGHT);
333         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_UNREAD,
334                                            GTK_JUSTIFY_RIGHT);
335         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_TOTAL,
336                                            GTK_JUSTIFY_RIGHT);
337         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_FOLDER,
338                                    prefs_common.folder_col_folder);
339         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_NEW,
340                                    prefs_common.folder_col_new);
341         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_UNREAD,        
342                                    prefs_common.folder_col_unread);
343         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_TOTAL,
344                                    prefs_common.folder_col_total);
345         gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
346         gtk_ctree_set_expander_style(GTK_CTREE(ctree),
347                                      GTK_CTREE_EXPANDER_SQUARE);
348         gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
349         gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
350
351         /* create popup factories */
352         folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
353         g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
354
355         /* don't let title buttons take key focus */
356         for (i = 0; i < N_FOLDER_COLS; i++)
357                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
358                                        GTK_CAN_FOCUS);
359
360         gtk_signal_connect(GTK_OBJECT(ctree), "key_press_event",
361                            GTK_SIGNAL_FUNC(folderview_key_pressed),
362                            folderview);
363         gtk_signal_connect(GTK_OBJECT(ctree), "button_press_event",
364                            GTK_SIGNAL_FUNC(folderview_button_pressed),
365                            folderview);
366         gtk_signal_connect(GTK_OBJECT(ctree), "button_release_event",
367                            GTK_SIGNAL_FUNC(folderview_button_released),
368                            folderview);
369         gtk_signal_connect(GTK_OBJECT(ctree), "tree_select_row",
370                            GTK_SIGNAL_FUNC(folderview_selected), folderview);
371         gtk_signal_connect(GTK_OBJECT(ctree), "start_drag",
372                            GTK_SIGNAL_FUNC(folderview_start_drag), folderview);
373         gtk_signal_connect(GTK_OBJECT(ctree), "drag_data_get",
374                            GTK_SIGNAL_FUNC(folderview_drag_data_get),
375                            folderview);
376
377         gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_expand",
378                                  GTK_SIGNAL_FUNC(folderview_tree_expanded),
379                                  folderview);
380         gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_collapse",
381                                  GTK_SIGNAL_FUNC(folderview_tree_collapsed),
382                                  folderview);
383
384         gtk_signal_connect(GTK_OBJECT(ctree), "resize_column",
385                            GTK_SIGNAL_FUNC(folderview_col_resized),
386                            folderview);
387
388         /* drop callback */
389         gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
390                           summary_drag_types, 1,
391                           GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
392         gtk_signal_connect(GTK_OBJECT(ctree), "drag_motion",
393                            GTK_SIGNAL_FUNC(folderview_drag_motion_cb),
394                            folderview);
395         gtk_signal_connect(GTK_OBJECT(ctree), "drag_leave",
396                            GTK_SIGNAL_FUNC(folderview_drag_leave_cb),
397                            folderview);
398         gtk_signal_connect(GTK_OBJECT(ctree), "drag_data_received",
399                            GTK_SIGNAL_FUNC(folderview_drag_received_cb),
400                            folderview);
401         gtk_signal_connect(GTK_OBJECT(ctree), "drag_end",
402                            GTK_SIGNAL_FUNC(folderview_drag_end_cb),
403                            folderview);
404
405         folderview->scrolledwin  = scrolledwin;
406         folderview->ctree        = ctree;
407
408         folderview->folder_update_callback_id =
409                 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
410         folderview->folder_item_update_callback_id =
411                 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
412
413         gtk_widget_show_all(scrolledwin);
414
415         folderview->target_list = gtk_target_list_new(folderview_drag_types, 1);
416         folderview_list = g_list_append(folderview_list, folderview);
417
418         return folderview;
419 }
420
421 void folderview_init(FolderView *folderview)
422 {
423         static GdkFont *boldfont = NULL;
424         static GdkFont *normalfont = NULL;
425         GtkWidget *ctree = folderview->ctree;
426         GtkWidget *label_new;
427         GtkWidget *label_unread;
428         GtkWidget *hbox_new;
429         GtkWidget *hbox_unread;
430         
431         gtk_widget_realize(ctree);
432         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
433         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
434         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
435         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
436         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
437         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
438         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
439         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
440         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
441         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
442         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
443         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
444         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
445         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
446         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
447         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
448         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
449         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
450         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
451         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
452         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
453         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
454
455         /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
456          * instead text (text overflows making them unreadable and ugly) */
457         stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
458                          &newxpm, &newxpmmask);
459         stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
460                          &unreadxpm, &unreadxpmmask);
461                 
462         label_new = gtk_pixmap_new(newxpm, newxpmmask);
463         label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
464
465         hbox_new = gtk_hbox_new(FALSE, 4);
466         hbox_unread = gtk_hbox_new(FALSE, 4);
467
468         /* left justified */
469         gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
470         gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
471         gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
472         gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
473
474         gtk_widget_show_all(hbox_new);
475         gtk_widget_show_all(hbox_unread);
476
477         gtk_clist_set_column_widget(GTK_CLIST(ctree),COL_NEW,hbox_new);
478         gtk_clist_set_column_widget(GTK_CLIST(ctree),COL_UNREAD,hbox_unread);
479                         
480         if (!normal_style) {
481                 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
482                 if (!normalfont)
483                         normalfont = gtkut_font_load(prefs_common.normalfont);
484                 if (normalfont)
485                         normal_style->font = normalfont;
486                 normal_color_style = gtk_style_copy(normal_style);
487                 normal_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
488
489                 gtk_widget_set_style(ctree, normal_style);
490         }
491
492         if (!bold_style) {
493                 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
494                 if (!boldfont)
495                         boldfont = gtkut_font_load(prefs_common.boldfont);
496                 if (boldfont)
497                         bold_style->font = boldfont;
498                 bold_color_style = gtk_style_copy(bold_style);
499                 bold_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
500
501                 bold_tgtfold_style = gtk_style_copy(bold_style);
502                 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
503         }
504 }
505
506 void folderview_set(FolderView *folderview)
507 {
508         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
509         MainWindow *mainwin = folderview->mainwin;
510
511         debug_print("Setting folder info...\n");
512         STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
513
514         main_window_cursor_wait(mainwin);
515
516         folderview->selected = NULL;
517         folderview->opened = NULL;
518
519         gtk_clist_freeze(GTK_CLIST(ctree));
520         gtk_clist_clear(GTK_CLIST(ctree));
521         gtk_clist_thaw(GTK_CLIST(ctree));
522         gtk_clist_freeze(GTK_CLIST(ctree));
523
524         folderview_set_folders(folderview);
525
526         gtk_clist_thaw(GTK_CLIST(ctree));
527         main_window_cursor_normal(mainwin);
528         STATUSBAR_POP(mainwin);
529 }
530
531 void folderview_set_all(void)
532 {
533         GList *list;
534
535         for (list = folderview_list; list != NULL; list = list->next)
536                 folderview_set((FolderView *)list->data);
537 }
538
539 void folderview_select(FolderView *folderview, FolderItem *item)
540 {
541         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
542         GtkCTreeNode *node;
543         GtkCTreeNode *old_selected = folderview->selected;
544
545         if (!item) return;
546
547         node = gtk_ctree_find_by_row_data(ctree, NULL, item);
548         if (node) folderview_select_node(folderview, node);
549
550         if (old_selected != node)
551                 folder_update_op_count();
552 }
553
554 static void mark_all_read_cb(FolderView *folderview, guint action,
555                              GtkWidget *widget)
556 {
557         FolderItem *item;
558
559         item = folderview_get_selected(folderview);
560         if (item == NULL)
561                 return;
562
563         folderutils_mark_all_read(item);
564 }
565
566 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
567 {
568         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
569
570         g_return_if_fail(node != NULL);
571
572         folderview->open_folder = TRUE;
573         gtkut_ctree_set_focus_row(ctree, node);
574         gtk_ctree_select(ctree, node);
575         if (folderview->summaryview->folder_item &&
576             folderview->summaryview->folder_item->total_msgs > 0)
577                 gtk_widget_grab_focus(folderview->summaryview->ctree);
578         else
579                 gtk_widget_grab_focus(folderview->ctree);
580
581         gtkut_ctree_expand_parent_all(ctree, node);
582 }
583
584 void folderview_unselect(FolderView *folderview)
585 {
586         if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
587                 gtk_ctree_collapse
588                         (GTK_CTREE(folderview->ctree), folderview->opened);
589
590         folderview->selected = folderview->opened = NULL;
591 }
592
593 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
594                                                  GtkCTreeNode *node)
595 {
596         FolderItem *item;
597
598         if (node)
599                 node = gtkut_ctree_node_next(ctree, node);
600         else
601                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
602
603         for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
604                 item = gtk_ctree_node_get_row_data(ctree, node);
605                 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
606                         return node;
607         }
608
609         return NULL;
610 }
611
612 void folderview_select_next_unread(FolderView *folderview)
613 {
614         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
615         GtkCTreeNode *node = NULL;
616
617         if ((node = folderview_find_next_unread(ctree, folderview->opened))
618             != NULL) {
619                 folderview_select_node(folderview, node);
620                 return;
621         }
622
623         if (!folderview->opened ||
624             folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
625                 return;
626         /* search again from the first node */
627         if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
628                 folderview_select_node(folderview, node);
629 }
630
631 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
632 {
633         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
634         static GtkCTreeNode *prev_row = NULL;
635         FolderItem *item;
636         gint new, unread, total;
637         gchar *new_str, *unread_str, *total_str;
638
639         if (!row) return;
640
641         item = gtk_ctree_node_get_row_data(ctree, row);
642         if (!item) return;
643
644         gtk_ctree_node_get_text(ctree, row, COL_NEW, &new_str);
645         gtk_ctree_node_get_text(ctree, row, COL_UNREAD, &unread_str);
646         gtk_ctree_node_get_text(ctree, row, COL_TOTAL, &total_str);
647         new = atoi(new_str);
648         unread = atoi(unread_str);
649         total = atoi(total_str);
650
651         prev_row = row;
652
653         folderview_update_node(folderview, row);
654 }
655
656 void folderview_append_item(FolderItem *item)
657 {
658         GList *list;
659
660         g_return_if_fail(item != NULL);
661         g_return_if_fail(item->folder != NULL);
662         if (folder_item_parent(item)) return;
663
664         for (list = folderview_list; list != NULL; list = list->next) {
665                 FolderView *folderview = (FolderView *)list->data;
666                 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
667                 GtkCTreeNode *node, *child;
668
669                 node = gtk_ctree_find_by_row_data(ctree, NULL, 
670                                                   folder_item_parent(item));
671                 if (node) {
672                         child = gtk_ctree_find_by_row_data(ctree, node, item);
673                         if (!child) {
674                                 gchar *text[N_FOLDER_COLS] =
675                                         {NULL, "0", "0", "0"};
676
677                                 gtk_clist_freeze(GTK_CLIST(ctree));
678
679                                 text[COL_FOLDER] = item->name;
680                                 child = gtk_ctree_insert_node
681                                         (ctree, node, NULL, text,
682                                          FOLDER_SPACING,
683                                          folderxpm, folderxpmmask,
684                                          folderopenxpm, folderopenxpmmask,
685                                          FALSE, FALSE);
686                                 gtk_ctree_node_set_row_data(ctree, child, item);
687                                 gtk_ctree_expand(ctree, node);
688                                 folderview_update_node(folderview, child);
689                                 folderview_sort_folders(folderview, node,
690                                                         item->folder);
691
692                                 gtk_clist_thaw(GTK_CLIST(ctree));
693                         }
694                 }
695         }
696 }
697
698 static void folderview_set_folders(FolderView *folderview)
699 {
700         GList *list;
701
702         list = folder_get_list();
703
704         for (; list != NULL; list = list->next)
705                 folderview_append_folder(folderview, FOLDER(list->data));
706 }
707
708 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
709                                       gpointer data)
710 {
711         GList *list;
712
713         for (list = folderview_list; list != NULL; list = list->next) {
714                 FolderView *folderview = (FolderView *)list->data;
715                 MainWindow *mainwin = folderview->mainwin;
716                 gchar *str;
717
718                 if (item->path)
719                         str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
720                                               item->folder->name, G_DIR_SEPARATOR,
721                                               item->path);
722                 else
723                         str = g_strdup_printf(_("Scanning folder %s ..."),
724                                               item->folder->name);
725
726                 STATUSBAR_PUSH(mainwin, str);
727                 STATUSBAR_POP(mainwin);
728                 g_free(str);
729         }
730 }
731
732 static GtkWidget *label_window_create(const gchar *str)
733 {
734         GtkWidget *window;
735         GtkWidget *label;
736
737         window = gtk_window_new(GTK_WINDOW_DIALOG);
738         gtk_widget_set_usize(window, 380, 60);
739         gtk_container_set_border_width(GTK_CONTAINER(window), 8);
740         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
741         gtk_window_set_title(GTK_WINDOW(window), str);
742         gtk_window_set_modal(GTK_WINDOW(window), TRUE);
743         gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
744         manage_window_set_transient(GTK_WINDOW(window));
745
746         label = gtk_label_new(str);
747         gtk_container_add(GTK_CONTAINER(window), label);
748         gtk_widget_show(label);
749
750         gtk_widget_show_now(window);
751
752         return window;
753 }
754
755 void folderview_rescan_tree(Folder *folder)
756 {
757         GtkWidget *window;
758
759         g_return_if_fail(folder != NULL);
760
761         if (!folder->klass->scan_tree) return;
762
763         inc_lock();
764         window = label_window_create(_("Rebuilding folder tree..."));
765
766         folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
767         folder_scan_tree(folder);
768         folder_set_ui_func(folder, NULL, NULL);
769
770         folderview_set_all();
771
772         gtk_widget_destroy(window);
773         inc_unlock();
774 }
775
776 /** folderview_check_new()
777  *  Scan and update the folder and return the 
778  *  count the number of new messages since last check. 
779  *  \param folder the folder to check for new messages
780  *  \return the number of new messages since last check
781  */
782 gint folderview_check_new(Folder *folder)
783 {
784         GList *list;
785         FolderItem *item;
786         FolderView *folderview;
787         GtkCTree *ctree;
788         GtkCTreeNode *node;
789         gint new_msgs = 0;
790         gint former_new_msgs = 0;
791         gint former_new = 0;
792
793         for (list = folderview_list; list != NULL; list = list->next) {
794                 folderview = (FolderView *)list->data;
795                 ctree = GTK_CTREE(folderview->ctree);
796
797                 inc_lock();
798                 main_window_lock(folderview->mainwin);
799                 gtk_widget_set_sensitive(folderview->ctree, FALSE);
800
801                 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
802                      node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
803                         item = gtk_ctree_node_get_row_data(ctree, node);
804                         if (!item || !item->path || !item->folder) continue;
805                         if (item->no_select) continue;
806                         if (folder && folder != item->folder) continue;
807                         if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
808                         if (!item->prefs->newmailcheck) continue;
809
810                         folderview_scan_tree_func(item->folder, item, NULL);
811                         former_new = item->new_msgs;
812                         if (folder_item_scan(item) < 0) {
813                                 if (folder && !FOLDER_IS_LOCAL(folder))
814                                         break;
815                         }
816                         folderview_update_node(folderview, node);
817                         new_msgs += item->new_msgs;
818                         former_new_msgs += former_new;
819                 }
820
821                 gtk_widget_set_sensitive(folderview->ctree, TRUE);
822                 main_window_unlock(folderview->mainwin);
823                 inc_unlock();
824         }
825
826         folder_write_list();
827         /* Number of new messages since last check is the just the difference 
828          * between former_new_msgs and new_msgs. If new_msgs is less than
829          * former_new_msgs, that would mean another session accessed the folder
830          * and the result is not well defined.
831          */
832         new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
833         return new_msgs;
834 }
835
836 void folderview_check_new_all(void)
837 {
838         GList *list;
839         GtkWidget *window;
840         FolderView *folderview;
841
842         folderview = (FolderView *)folderview_list->data;
843
844         inc_lock();
845         main_window_lock(folderview->mainwin);
846         window = label_window_create
847                 (_("Checking for new messages in all folders..."));
848
849         list = folder_get_list();
850         for (; list != NULL; list = list->next) {
851                 Folder *folder = list->data;
852
853                 folderview_check_new(folder);
854         }
855
856         folder_write_list();
857         folderview_set_all();
858
859         gtk_widget_destroy(window);
860         main_window_unlock(folderview->mainwin);
861         inc_unlock();
862 }
863
864 static gboolean folderview_search_new_recursive(GtkCTree *ctree,
865                                                 GtkCTreeNode *node)
866 {
867         FolderItem *item;
868
869         if (node) {
870                 item = gtk_ctree_node_get_row_data(ctree, node);
871                 if (item) {
872                         if (item->new_msgs > 0 ||
873                             (item->stype == F_QUEUE && item->total_msgs > 0))
874                                 return TRUE;
875                 }
876                 node = GTK_CTREE_ROW(node)->children;
877         } else
878                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
879
880         while (node) {
881                 if (folderview_search_new_recursive(ctree, node) == TRUE)
882                         return TRUE;
883                 node = GTK_CTREE_ROW(node)->sibling;
884         }
885
886         return FALSE;
887 }
888
889 static gboolean folderview_have_new_children(FolderView *folderview,
890                                              GtkCTreeNode *node)
891 {
892         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
893
894         if (!node)
895                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
896         if (!node)
897                 return FALSE;
898
899         node = GTK_CTREE_ROW(node)->children;
900
901         while (node) {
902                 if (folderview_search_new_recursive(ctree, node) == TRUE)
903                         return TRUE;
904                 node = GTK_CTREE_ROW(node)->sibling;
905         }
906
907         return FALSE;
908 }
909
910 static gboolean folderview_search_unread_recursive(GtkCTree *ctree,
911                                                    GtkCTreeNode *node)
912 {
913         FolderItem *item;
914
915         if (node) {
916                 item = gtk_ctree_node_get_row_data(ctree, node);
917                 if (item) {
918                         if (item->unread_msgs > 0 ||
919                             (item->stype == F_QUEUE && item->total_msgs > 0))
920                                 return TRUE;
921                 }
922                 node = GTK_CTREE_ROW(node)->children;
923         } else
924                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
925
926         while (node) {
927                 if (folderview_search_unread_recursive(ctree, node) == TRUE)
928                         return TRUE;
929                 node = GTK_CTREE_ROW(node)->sibling;
930         }
931
932         return FALSE;
933 }
934
935 static gboolean folderview_have_unread_children(FolderView *folderview,
936                                                 GtkCTreeNode *node)
937 {
938         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
939
940         if (!node)
941                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
942         if (!node)
943                 return FALSE;
944
945         node = GTK_CTREE_ROW(node)->children;
946
947         while (node) {
948                 if (folderview_search_unread_recursive(ctree, node) == TRUE)
949                         return TRUE;
950                 node = GTK_CTREE_ROW(node)->sibling;
951         }
952
953         return FALSE;
954 }
955
956 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
957 {
958         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
959         GtkStyle *style = NULL;
960         GtkStyle *color_style = NULL;
961         FolderItem *item;
962         GdkPixmap *xpm, *openxpm;
963         GdkBitmap *mask, *openmask;
964         gchar *name;
965         gchar *str;
966         gboolean add_unread_mark;
967         gboolean use_bold, use_color;
968
969         item = gtk_ctree_node_get_row_data(ctree, node);
970         g_return_if_fail(item != NULL);
971
972         switch (item->stype) {
973         case F_INBOX:
974                 if (item->hide_read_msgs) {
975                         xpm = inboxhrmxpm;
976                         mask = inboxhrmxpmmask;
977                         openxpm = inboxopenhrmxpm;
978                         openmask = inboxopenhrmxpmmask;
979                 } else {
980                         xpm = inboxxpm;
981                         mask = inboxxpmmask;
982                         openxpm = inboxopenxpm;
983                         openmask = inboxopenxpmmask;
984                 }
985                 break;
986         case F_OUTBOX:
987                 if (item->hide_read_msgs) {
988                         xpm = outboxhrmxpm;
989                         mask = outboxhrmxpmmask;
990                         openxpm = outboxopenhrmxpm;
991                         openmask = outboxopenhrmxpmmask;
992                 } else {
993                         xpm = outboxxpm;
994                         mask = outboxxpmmask;
995                         openxpm = outboxopenxpm;
996                         openmask = outboxopenxpmmask;
997                 }
998                 break;
999         case F_QUEUE:
1000                 if (item->hide_read_msgs) {
1001                         xpm = queuehrmxpm;
1002                         mask = queuehrmxpmmask;
1003                         openxpm = queueopenhrmxpm;
1004                         openmask = queueopenhrmxpmmask;
1005                 } else {
1006                         xpm = queuexpm;
1007                         mask = queuexpmmask;
1008                         openxpm = queueopenxpm;
1009                         openmask = queueopenxpmmask;
1010                 }
1011                 break;
1012         case F_TRASH:
1013                 if (item->hide_read_msgs) {
1014                         xpm = trashhrmxpm;
1015                         mask = trashhrmxpmmask;
1016                         openxpm = trashopenhrmxpm;
1017                         openmask = trashopenhrmxpmmask;
1018                 } else {
1019                         xpm = trashxpm;
1020                         mask = trashxpmmask;
1021                         openxpm = trashopenxpm;
1022                         openmask = trashopenxpmmask;
1023                 }
1024                 break;
1025         case F_DRAFT:
1026                 xpm = draftsxpm;
1027                 mask = draftsxpmmask;
1028                 openxpm = draftsopenxpm;
1029                 openmask = draftsopenxpmmask;
1030                 break;
1031         default:
1032                 if (item->hide_read_msgs) {
1033                         xpm = folderhrmxpm;
1034                         mask = folderhrmxpmmask;
1035                         openxpm = folderopenhrmxpm;
1036                         openmask = folderopenhrmxpmmask;
1037                 } else {
1038                         xpm = folderxpm;
1039                         mask = folderxpmmask;
1040                         openxpm = folderopenxpm;
1041                         openmask = folderopenxpmmask;
1042                 }
1043         }
1044         name = folder_item_get_name(item);
1045
1046         if (!GTK_CTREE_ROW(node)->expanded &&
1047             folderview_have_unread_children(folderview, node))
1048                 add_unread_mark = TRUE;
1049         else
1050                 add_unread_mark = FALSE;
1051
1052         if (item->stype == F_QUEUE && item->total_msgs > 0 &&
1053             prefs_common.display_folder_unread) {
1054                 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1055                                       add_unread_mark ? "+" : "");
1056                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1057                                         xpm, mask, openxpm, openmask,
1058                                         FALSE, GTK_CTREE_ROW(node)->expanded);
1059                 g_free(str);
1060         } else if ((item->unread_msgs > 0 || add_unread_mark) &&
1061                  prefs_common.display_folder_unread) {
1062
1063                 if (item->unread_msgs > 0)
1064                         str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1065                                               add_unread_mark ? "+" : "", 
1066                                               item->unreadmarked_msgs > 0 ? "!":"");
1067                 else
1068                         str = g_strdup_printf("%s (+)", name);
1069                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1070                                         xpm, mask, openxpm, openmask,
1071                                         FALSE, GTK_CTREE_ROW(node)->expanded);
1072                 g_free(str);
1073         } else {
1074                 str = g_strdup_printf("%s%s", name, 
1075                                       item->unreadmarked_msgs > 0 ? " (!)":"");
1076         
1077                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1078                                         xpm, mask, openxpm, openmask,
1079                                         FALSE, GTK_CTREE_ROW(node)->expanded);
1080                 g_free(str);
1081         }
1082         g_free(name);
1083
1084         if (!folder_item_parent(item)) {
1085                 gtk_ctree_node_set_text(ctree, node, COL_NEW,    "-");
1086                 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, "-");
1087                 gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  "-");
1088         } else {
1089                 gtk_ctree_node_set_text(ctree, node, COL_NEW,    itos(item->new_msgs));
1090                 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, itos(item->unread_msgs));
1091                 gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  itos(item->total_msgs));
1092         }
1093
1094         if (item->stype == F_OUTBOX || item->stype == F_DRAFT ||
1095             item->stype == F_TRASH) {
1096                 use_bold = use_color = FALSE;
1097         } else if (item->stype == F_QUEUE) {
1098                 /* highlight queue folder if there are any messages */
1099                 use_bold = use_color = (item->total_msgs > 0);
1100         } else {
1101                 /* if unread messages exist, print with bold font */
1102                 use_bold = (item->unread_msgs > 0) || add_unread_mark;
1103                 /* if new messages exist, print with colored letter */
1104                 use_color =
1105                         (item->new_msgs > 0) ||
1106                         (add_unread_mark &&
1107                          folderview_have_new_children(folderview, node));       
1108         }
1109
1110         gtk_ctree_node_set_foreground(ctree, node, NULL);
1111
1112         if (use_bold) {
1113                 if (item->prefs->color > 0 && !use_color) {
1114                         GdkColor gdk_color;
1115
1116                         gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1117                         color_style = gtk_style_copy(bold_style);
1118                         color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1119                         style = color_style;
1120                 } else if (use_color)
1121                         style = bold_color_style;
1122                 else
1123                         style = bold_style;
1124                 if (item->op_count > 0) {
1125                         style = bold_tgtfold_style;
1126                 }
1127         } else if (use_color) {
1128                 style = normal_color_style;
1129                 gtk_ctree_node_set_foreground(ctree, node,
1130                                               &folderview->color_new);
1131         } else if (item->op_count > 0) {
1132                 style = bold_tgtfold_style;
1133         } else if (item->prefs->color > 0) {
1134                 GdkColor gdk_color;
1135
1136                 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1137                 color_style = gtk_style_copy(normal_style);
1138                 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1139                 style = color_style;
1140         } else {
1141                 style = normal_style;
1142         }
1143
1144         gtk_ctree_node_set_row_style(ctree, node, style);
1145
1146         if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1147                 folderview_update_node(folderview, node);
1148 }
1149
1150 #if !CLAWS /* keep it here for syncs */
1151 void folderview_update_item(FolderItem *item, gboolean update_summary)
1152 {
1153         GList *list;
1154         FolderView *folderview;
1155         GtkCTree *ctree;
1156         GtkCTreeNode *node;
1157
1158         g_return_if_fail(item != NULL);
1159
1160         for (list = folderview_list; list != NULL; list = list->next) {
1161                 folderview = (FolderView *)list->data;
1162                 ctree = GTK_CTREE(folderview->ctree);
1163
1164                 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1165                 if (node) {
1166                         folderview_update_node(folderview, node);
1167                         if (update_summary && folderview->opened == node)
1168                                 summary_show(folderview->summaryview,
1169                                              item, FALSE);
1170                 }
1171         }
1172 }
1173 #endif
1174
1175 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1176 {
1177         FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1178         FolderView *folderview = (FolderView *)data;
1179         GtkCTree *ctree;
1180         GtkCTreeNode *node;
1181
1182         g_return_val_if_fail(update_info != NULL, TRUE);
1183         g_return_val_if_fail(update_info->item != NULL, TRUE);
1184         g_return_val_if_fail(folderview != NULL, FALSE);
1185
1186         ctree = GTK_CTREE(folderview->ctree);
1187
1188         node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1189         if (node) {
1190                 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1191                         folderview_update_node(folderview, node);
1192                 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1193                         summary_show(folderview->summaryview, update_info->item);
1194         }
1195         
1196         return FALSE;
1197 }
1198
1199 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1200                                                 gpointer data)
1201 {
1202         /* CLAWS: share this joy with other hook functions ... */
1203         folder_item_update((FolderItem *)key, 
1204                            (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1205 }
1206
1207 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1208 {
1209         GList *list;
1210         FolderItemUpdateFlags flags;
1211         
1212         flags = update_summary ?  F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1213                 : 0;
1214         for (list = folderview_list; list != NULL; list = list->next)
1215                 g_hash_table_foreach(table, folderview_update_item_foreach_func, 
1216                                      GINT_TO_POINTER(flags));
1217 }
1218
1219 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1220                                       GNode *gnode, GtkCTreeNode *cnode,
1221                                       gpointer data)
1222 {
1223         FolderView *folderview = (FolderView *)data;
1224         FolderItem *item = FOLDER_ITEM(gnode->data);
1225
1226         g_return_val_if_fail(item != NULL, FALSE);
1227
1228         gtk_ctree_node_set_row_data(ctree, cnode, item);
1229         folderview_update_node(folderview, cnode);
1230
1231         return TRUE;
1232 }
1233
1234 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1235                                    gpointer data)
1236 {
1237         FolderView *folderview = (FolderView *)data;
1238         FolderItem *item;
1239
1240         if (GTK_CTREE_ROW(node)->children) {
1241                 item = gtk_ctree_node_get_row_data(ctree, node);
1242                 g_return_if_fail(item != NULL);
1243
1244                 if (!item->collapsed)
1245                         gtk_ctree_expand(ctree, node);
1246                 else
1247                         folderview_update_node(folderview, node);
1248         }
1249 }
1250
1251 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1252                                GtkCTreeNode *root, GtkCTreeNode **prev)
1253 {
1254         if (item) {
1255                 GtkCTreeNode *node, *parent, *sibling;
1256
1257                 node = gtk_ctree_find_by_row_data(ctree, root, item);
1258                 if (!node)
1259                         g_warning("%s not found.\n", item->path);
1260                 else {
1261                         parent = GTK_CTREE_ROW(node)->parent;
1262                         if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1263                                 sibling = GTK_CTREE_ROW(*prev)->sibling;
1264                         else
1265                                 sibling = GTK_CTREE_ROW(parent)->children;
1266                         while (sibling) {
1267                                 FolderItem *tmp;
1268
1269                                 tmp = gtk_ctree_node_get_row_data
1270                                         (ctree, sibling);
1271                                 if (tmp->stype != F_NORMAL)
1272                                         sibling = GTK_CTREE_ROW(sibling)->sibling;
1273                                 else
1274                                         break;
1275                         }
1276                         if (node != sibling)
1277                                 gtk_ctree_move(ctree, node, parent, sibling);
1278                 }
1279
1280                 *prev = node;
1281         }
1282 }
1283
1284 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1285                                     Folder *folder)
1286 {
1287         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1288         GtkCTreeNode *prev = NULL;
1289
1290         gtk_sctree_sort_recursive(ctree, root);
1291
1292         if (root && GTK_CTREE_ROW(root)->parent) return;
1293
1294         set_special_folder(ctree, folder->inbox, root, &prev);
1295         set_special_folder(ctree, folder->outbox, root, &prev);
1296         set_special_folder(ctree, folder->draft, root, &prev);
1297         set_special_folder(ctree, folder->queue, root, &prev);
1298         set_special_folder(ctree, folder->trash, root, &prev);
1299 }
1300
1301 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1302 {
1303         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1304         GtkCTreeNode *root;
1305
1306         g_return_if_fail(folder != NULL);
1307
1308         root = gtk_ctree_insert_gnode(ctree, NULL, NULL, folder->node,
1309                                       folderview_gnode_func, folderview);
1310         gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1311                                 folderview);
1312         folderview_sort_folders(folderview, root, folder);
1313 }
1314
1315 /* callback functions */
1316
1317 static void folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1318                                       FolderView *folderview)
1319 {
1320         GtkCList *clist = GTK_CLIST(ctree);
1321         gint prev_row = -1, row = -1, column = -1;
1322         FolderItem *item;
1323         Folder *folder;
1324         FolderViewPopup *fpopup;
1325         GtkItemFactory *fpopup_factory;
1326         GtkWidget *popup;
1327
1328         if (!event) return;
1329
1330         if (event->button == 1) {
1331                 folderview->open_folder = TRUE;
1332                 return;
1333         }
1334
1335         if (event->button == 2 || event->button == 3) {
1336                 /* right clicked */
1337                 if (clist->selection) {
1338                         GtkCTreeNode *node;
1339
1340                         node = GTK_CTREE_NODE(clist->selection->data);
1341                         if (node)
1342                                 prev_row = gtkut_ctree_get_nth_from_node
1343                                         (GTK_CTREE(ctree), node);
1344                 }
1345
1346                 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1347                                                   &row, &column))
1348                         return;
1349                 if (prev_row != row) {
1350                         gtk_clist_unselect_all(clist);
1351                         if (event->button == 2)
1352                                 folderview_select_node
1353                                         (folderview,
1354                                          gtk_ctree_node_nth(GTK_CTREE(ctree),
1355                                                             row));
1356                         else
1357                                 gtk_clist_select_row(clist, row, column);
1358                 }
1359         }
1360
1361         if (event->button != 3) return;
1362
1363         item = gtk_clist_get_row_data(clist, row);
1364         g_return_if_fail(item != NULL);
1365         g_return_if_fail(item->folder != NULL);
1366         folder = item->folder;
1367
1368         fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1369         if (fpopup != NULL)
1370                 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1371         else {
1372                 fpopup = g_hash_table_lookup(folderview_popups, "common");
1373                 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1374         }
1375
1376         if (fpopup->set_sensitivity != NULL)
1377                 fpopup->set_sensitivity(fpopup_factory, item);
1378
1379 #define SET_SENS(name, sens) \
1380         menu_set_sensitive(fpopup_factory, name, sens)
1381
1382         SET_SENS("/Mark all read", item->unread_msgs >= 1);
1383         SET_SENS("/Search folder...", item->total_msgs >= 1 && 
1384                  folderview->selected == folderview->opened);
1385         SET_SENS("/Properties...", TRUE);
1386         SET_SENS("/Processing...", item->node->parent != NULL);
1387
1388 #undef SET_SENS
1389
1390         popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1391         gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1392                        event->button, event->time);
1393 }
1394
1395 static void folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1396                                        FolderView *folderview)
1397 {
1398         if (!event) return;
1399
1400         if (event->button == 1 && folderview->open_folder == FALSE &&
1401             folderview->opened != NULL) {
1402                 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1403                                           folderview->opened);
1404                 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1405         }
1406 }
1407
1408 static void folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1409                                    FolderView *folderview)
1410 {
1411         if (!event) return;
1412
1413         switch (event->keyval) {
1414         case GDK_Return:
1415                 if (folderview->selected) {
1416                         folderview_select_node(folderview,
1417                                                folderview->selected);
1418                 }
1419                 break;
1420         case GDK_space:
1421                 if (folderview->selected) {
1422                         if (folderview->opened == folderview->selected &&
1423                             (!folderview->summaryview->folder_item ||
1424                              folderview->summaryview->folder_item->total_msgs == 0))
1425                                 folderview_select_next_unread(folderview);
1426                         else
1427                                 folderview_select_node(folderview,
1428                                                        folderview->selected);
1429                 }
1430                 break;
1431         default:
1432                 break;
1433         }
1434 }
1435
1436 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1437                                 gint column, FolderView *folderview)
1438 {
1439         static gboolean can_select = TRUE;      /* exclusive lock */
1440         gboolean opened;
1441         FolderItem *item;
1442         gchar *buf;
1443
1444         folderview->selected = row;
1445
1446         if (folderview->opened == row) {
1447                 folderview->open_folder = FALSE;
1448                 return;
1449         }
1450
1451         if (!can_select || summary_is_locked(folderview->summaryview)) {
1452                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1453                 gtk_ctree_select(ctree, folderview->opened);
1454                 return;
1455         }
1456
1457         if (!folderview->open_folder) return;
1458
1459         item = gtk_ctree_node_get_row_data(ctree, row);
1460         if (!item) return;
1461
1462         can_select = FALSE;
1463
1464         /* Save cache for old folder */
1465         /* We don't want to lose all caches if sylpheed crashed */
1466         if (folderview->opened) {
1467                 FolderItem *olditem;
1468                 
1469                 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
1470                 if (olditem) {
1471                         /* will be null if we just moved the previously opened folder */
1472                         summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
1473                         folder_item_close(olditem);
1474                 }
1475         }
1476
1477         /* CLAWS: set compose button type: news folder items 
1478          * always have a news folder as parent */
1479         if (item->folder) 
1480                 toolbar_set_compose_button
1481                         (folderview->mainwin->toolbar,
1482                          FOLDER_TYPE(item->folder) == F_NEWS ? 
1483                          COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
1484
1485         if (item->path)
1486                 debug_print("Folder %s is selected\n", item->path);
1487
1488         if (!GTK_CTREE_ROW(row)->children)
1489                 gtk_ctree_expand(ctree, row);
1490         if (folderview->opened &&
1491             !GTK_CTREE_ROW(folderview->opened)->children)
1492                 gtk_ctree_collapse(ctree, folderview->opened);
1493
1494         /* ungrab the mouse event */
1495         if (GTK_WIDGET_HAS_GRAB(ctree)) {
1496                 gtk_grab_remove(GTK_WIDGET(ctree));
1497                 if (gdk_pointer_is_grabbed())
1498                         gdk_pointer_ungrab(GDK_CURRENT_TIME);
1499         }
1500
1501         /* Open Folder */
1502         buf = g_strdup_printf(_("Opening Folder %s..."), item->path ? 
1503                                         item->path : "(null)");
1504         debug_print("%s\n", buf);
1505         STATUSBAR_PUSH(folderview->mainwin, buf);
1506         g_free(buf);
1507
1508         main_window_cursor_wait(folderview->mainwin);
1509
1510         if (folder_item_open(item) != 0) {
1511                 main_window_cursor_normal(folderview->mainwin);
1512                 STATUSBAR_POP(folderview->mainwin);
1513
1514                 alertpanel_error(_("Folder could not be opened."));
1515
1516                 folderview->open_folder = FALSE;
1517                 can_select = TRUE;
1518
1519                 return;
1520         }
1521
1522         main_window_cursor_normal(folderview->mainwin);
1523
1524         /* Show messages */
1525         summary_set_prefs_from_folderitem(folderview->summaryview, item);
1526         opened = summary_show(folderview->summaryview, item);
1527         
1528         folder_clean_cache_memory();
1529
1530         if (!opened) {
1531                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1532                 gtk_ctree_select(ctree, folderview->opened);
1533         } else {
1534                 folderview->opened = row;
1535                 if (gtk_ctree_node_is_visible(ctree, row)
1536                     != GTK_VISIBILITY_FULL)
1537                         gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
1538         }
1539
1540         STATUSBAR_POP(folderview->mainwin);
1541
1542         folderview->open_folder = FALSE;
1543         can_select = TRUE;
1544 }
1545
1546 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
1547                                      FolderView *folderview)
1548 {
1549         FolderItem *item;
1550
1551         item = gtk_ctree_node_get_row_data(ctree, node);
1552         g_return_if_fail(item != NULL);
1553         item->collapsed = FALSE;
1554         folderview_update_node(folderview, node);
1555 }
1556
1557 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
1558                                       FolderView *folderview)
1559 {
1560         FolderItem *item;
1561
1562         item = gtk_ctree_node_get_row_data(ctree, node);
1563         g_return_if_fail(item != NULL);
1564         item->collapsed = TRUE;
1565         folderview_update_node(folderview, node);
1566 }
1567
1568 static void folderview_popup_close(GtkMenuShell *menu_shell,
1569                                    FolderView *folderview)
1570 {
1571         if (!folderview->opened) return;
1572
1573         gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
1574                                   folderview->opened);
1575         gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
1576 }
1577
1578 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
1579                                    FolderView *folderview)
1580 {
1581         switch (column) {
1582         case COL_FOLDER:
1583                 prefs_common.folder_col_folder = width;
1584                 break;
1585         case COL_NEW:
1586                 prefs_common.folder_col_new = width;
1587                 break;
1588         case COL_UNREAD:
1589                 prefs_common.folder_col_unread = width;
1590                 break;
1591         case COL_TOTAL:
1592                 prefs_common.folder_col_total = width;
1593                 break;
1594         default:
1595                 break;
1596         }
1597 }
1598
1599 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
1600 {
1601         GNode *srcnode;
1602
1603         folderview_create_folder_node(folderview, item);
1604         
1605         srcnode = item->folder->node;   
1606         srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1607         srcnode = srcnode->children;
1608         while (srcnode != NULL) {
1609                 if (srcnode && srcnode->data) {
1610                         FolderItem *next_item = (FolderItem*) srcnode->data;
1611                         folderview_create_folder_node_recursive(folderview, next_item);
1612                 }
1613                 srcnode = srcnode->next;
1614         }
1615 }
1616
1617 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
1618 {
1619         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1620         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1621         GtkCTreeNode *node, *parent_node;
1622         
1623         parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
1624         if (parent_node == NULL)
1625                 return;
1626
1627         gtk_clist_freeze(GTK_CLIST(ctree));
1628
1629         text[COL_FOLDER] = item->name;
1630         node = gtk_ctree_insert_node(ctree, parent_node, NULL, text,
1631                                      FOLDER_SPACING,
1632                                      folderxpm, folderxpmmask,
1633                                      folderopenxpm, folderopenxpmmask,
1634                                      FALSE, FALSE);
1635         gtk_ctree_expand(ctree, parent_node);
1636         gtk_ctree_node_set_row_data(ctree, node, item);
1637         if (normal_style)
1638                 gtk_ctree_node_set_row_style(ctree, node, normal_style);
1639         folderview_sort_folders(folderview, folderview->selected, item->folder);
1640
1641         gtk_clist_thaw(GTK_CLIST(ctree));
1642 }
1643
1644 static void folderview_search_cb(FolderView *folderview, guint action,
1645                                  GtkWidget *widget)
1646 {
1647         summary_search(folderview->summaryview);
1648 }
1649
1650 static void folderview_property_cb(FolderView *folderview, guint action,
1651                                    GtkWidget *widget)
1652 {
1653         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1654         FolderItem *item;
1655
1656         if (!folderview->selected) return;
1657
1658         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1659         g_return_if_fail(item != NULL);
1660         g_return_if_fail(item->folder != NULL);
1661
1662         if (folder_item_parent(item) == NULL && item->folder->account)
1663                 account_open(item->folder->account);
1664         else {
1665                 prefs_folder_item_open(item);
1666         }
1667 }
1668
1669 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
1670 {
1671         GSList *list = NULL;
1672         GSList *done = NULL;
1673         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1674         
1675         for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
1676                 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
1677                 &&  list->data != node) {
1678                         gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
1679                         done = g_slist_append(done, GTK_CTREE_NODE(list->data));
1680                 }
1681         }
1682         for (list = done; list != NULL; list = g_slist_next(list)) {
1683                 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse, 
1684                                                                  list->data);
1685         }
1686         g_slist_free(done);
1687 }
1688
1689 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
1690                             FolderItem *to_folder)
1691 {
1692         FolderItem *from_parent = NULL;
1693         FolderItem *new_folder = NULL;
1694         GtkCTreeNode *src_node = NULL;
1695         gchar *buf;
1696         gint status;
1697
1698         g_return_if_fail(folderview != NULL);
1699         g_return_if_fail(from_folder != NULL);
1700         g_return_if_fail(to_folder != NULL);
1701
1702         src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
1703         from_parent = folder_item_parent(from_folder);
1704         buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
1705         STATUSBAR_PUSH(folderview->mainwin, buf);
1706         g_free(buf);
1707         summary_clear_all(folderview->summaryview);
1708         folderview->opened = NULL;
1709         folderview->selected = NULL;
1710         gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
1711         inc_lock();
1712         main_window_cursor_wait(folderview->mainwin);
1713         statusbar_verbosity_set(TRUE);
1714         folder_item_update_freeze();
1715         if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
1716                 statusbar_verbosity_set(FALSE);
1717                 main_window_cursor_normal(folderview->mainwin);
1718                 STATUSBAR_POP(folderview->mainwin);
1719                 folder_item_update_thaw();
1720                 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
1721
1722                 folderview_sort_folders(folderview, 
1723                         gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), 
1724                                 NULL, folder_item_parent(new_folder)), new_folder->folder);
1725                 folderview_select(folderview, new_folder);
1726         } else {
1727                 statusbar_verbosity_set(FALSE);         
1728                 main_window_cursor_normal(folderview->mainwin);
1729                 STATUSBAR_POP(folderview->mainwin);
1730                 folder_item_update_thaw();
1731                 switch (status) {
1732                 case F_MOVE_FAILED_DEST_IS_PARENT:
1733                         alertpanel_error(_("Source and destination are the same."));
1734                         break;
1735                 case F_MOVE_FAILED_DEST_IS_CHILD:
1736                         alertpanel_error(_("Can't move a folder to one of its children."));
1737                         break;
1738                 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
1739                         alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
1740                         break;
1741                 default:
1742                         alertpanel_error(_("Move failed!"));
1743                         break;
1744                 }
1745         }       
1746         inc_unlock();           
1747         gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
1748 }
1749
1750 static gint folderview_clist_compare(GtkCList *clist,
1751                                      gconstpointer ptr1, gconstpointer ptr2)
1752 {
1753         FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
1754         FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
1755
1756         if (!item1->name)
1757                 return (item2->name != NULL);
1758         if (!item2->name)
1759                 return -1;
1760
1761         return g_strcasecmp(item1->name, item2->name);
1762 }
1763
1764 static void folderview_processing_cb(FolderView *folderview, guint action,
1765                                      GtkWidget *widget)
1766 {
1767         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1768         FolderItem *item;
1769
1770         if (!folderview->selected) return;
1771
1772         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1773         g_return_if_fail(item != NULL);
1774         g_return_if_fail(item->folder != NULL);
1775
1776         prefs_filtering_open(&item->prefs->processing,
1777                              _("Processing configuration"), NULL, NULL);
1778 }
1779
1780 void folderview_set_target_folder_color(gint color_op) 
1781 {
1782         gint firstone = 1;
1783         GList *list;
1784         FolderView *folderview;
1785
1786         for (list = folderview_list; list != NULL; list = list->next) {
1787                 folderview = (FolderView *)list->data;
1788                 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
1789                 if (firstone) {
1790                         bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
1791                                 folderview->color_op;
1792                         firstone = 0;
1793                 }
1794         }
1795 }
1796
1797 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
1798 {
1799         folderview_init(folderview);
1800         folderview_set_all();
1801 }
1802
1803 static void drag_state_stop(FolderView *folderview)
1804 {
1805         if (folderview->drag_timer)
1806                 gtk_timeout_remove(folderview->drag_timer);
1807         folderview->drag_timer = 0;
1808         folderview->drag_node = NULL;
1809 }
1810
1811 static gint folderview_defer_expand(FolderView *folderview)
1812 {
1813         if (folderview->drag_node) {
1814                 folderview_recollapse_nodes(folderview, folderview->drag_node);
1815                 if (folderview->drag_item->collapsed) {
1816                         gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
1817                         folderview->nodes_to_recollapse = g_slist_append
1818                                 (folderview->nodes_to_recollapse, folderview->drag_node);
1819                 }
1820         }
1821         folderview->drag_item  = NULL;
1822         folderview->drag_timer = 0;
1823         return FALSE;
1824 }
1825
1826 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
1827 {
1828         /* the idea is that we call drag_state_start() whenever we want expansion to
1829          * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
1830          * we need to call drag_state_stop() */
1831         drag_state_stop(folderview);
1832         /* request expansion */
1833         if (0 != (folderview->drag_timer = gtk_timeout_add
1834                         (prefs_common.hover_timeout, 
1835                          (GtkFunction)folderview_defer_expand,
1836                          folderview))) {
1837                 folderview->drag_node = node;
1838                 folderview->drag_item = item;
1839         }                        
1840 }
1841
1842 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
1843                                   FolderView       *folderview)
1844 {
1845         GdkDragContext *context;
1846
1847         g_return_if_fail(folderview != NULL);
1848         if (folderview->selected == NULL) return;
1849         if (folderview->nodes_to_recollapse) 
1850                 g_slist_free(folderview->nodes_to_recollapse);
1851         folderview->nodes_to_recollapse = NULL;
1852         context = gtk_drag_begin(widget, folderview->target_list,
1853                                  GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
1854         gtk_drag_set_icon_default(context);
1855 }
1856
1857 static void folderview_drag_data_get(GtkWidget        *widget,
1858                                      GdkDragContext   *drag_context,
1859                                      GtkSelectionData *selection_data,
1860                                      guint             info,
1861                                      guint             time,
1862                                      FolderView       *folderview)
1863 {
1864         FolderItem *item;
1865         GList *cur;
1866         gchar *source = NULL;
1867
1868         for (cur = GTK_CLIST(folderview->ctree)->selection;
1869              cur != NULL; cur = cur->next) {
1870                 item = gtk_ctree_node_get_row_data
1871                         (GTK_CTREE(folderview->ctree), 
1872                          GTK_CTREE_NODE(cur->data));
1873                 if (item) {
1874                         source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
1875                         gtk_selection_data_set(selection_data,
1876                                                selection_data->target, 8,
1877                                                source, strlen(source));
1878                         break;
1879                 } else
1880                         return;
1881         }
1882 }
1883
1884 gboolean folderview_update_folder(gpointer source, gpointer userdata)
1885 {
1886         FolderUpdateData *hookdata;
1887         FolderView *folderview;
1888         GtkWidget *ctree;
1889
1890         hookdata = source;
1891         folderview = (FolderView *) userdata;   
1892         g_return_val_if_fail(hookdata != NULL, FALSE);
1893         g_return_val_if_fail(folderview != NULL, FALSE);
1894
1895         ctree = folderview->ctree;
1896         g_return_val_if_fail(ctree != NULL, FALSE);
1897
1898         if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
1899                 folderview_create_folder_node(folderview, hookdata->item);
1900         else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
1901                 GtkCTreeNode *node;
1902
1903                 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
1904                 if (node != NULL)
1905                         gtk_ctree_remove_node(GTK_CTREE(ctree), node);
1906         } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
1907                 folderview_set(folderview);
1908
1909         return FALSE;
1910 }
1911
1912 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
1913                                           GdkDragContext *context,
1914                                           gint            x,
1915                                           gint            y,
1916                                           guint           time,
1917                                           FolderView     *folderview)
1918 {
1919         gint row, column;
1920         FolderItem *item, *src_item = NULL;
1921         GtkCTreeNode *node = NULL;
1922         gboolean acceptable = FALSE;
1923         gint height = folderview->ctree->allocation.height;
1924         gint total_height = folderview->ctree->requisition.height;
1925         GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
1926                                 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1927         gfloat vpos = pos->value;
1928
1929         if (gtk_clist_get_selection_info
1930                 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
1931                 GtkWidget *srcwidget;
1932
1933                 if (y > height - 24 && height + vpos < total_height)
1934                         gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
1935
1936                 if (y < 24 && y > 0)
1937                         gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
1938
1939                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
1940                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
1941                 src_item = folderview->summaryview->folder_item;
1942
1943                 srcwidget = gtk_drag_get_source_widget(context);
1944                 if (srcwidget == folderview->summaryview->ctree) {
1945                         /* comes from summaryview */
1946                         /* we are copying messages, so only accept folder items that are not
1947                            the source item, are no root items and can copy messages */
1948                         if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
1949                             src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
1950                                 acceptable = TRUE;
1951                 } else if (srcwidget == folderview->ctree) {
1952                         /* comes from folderview */
1953                         /* we are moving folder items, only accept folders that are not
1954                            the source items and can copy messages and create folder items */
1955                         if (item && item->folder && src_item && src_item != item &&
1956                             FOLDER_CLASS(item->folder)->copy_msg != NULL &&
1957                             FOLDER_CLASS(item->folder)->create_folder != NULL)
1958                                 acceptable = TRUE;
1959                 }
1960         }
1961
1962         if (acceptable || (src_item && src_item == item))
1963                 drag_state_start(folderview, node, item);
1964         
1965         if (acceptable) {
1966                 gtk_signal_handler_block_by_func
1967                         (GTK_OBJECT(widget),
1968                          GTK_SIGNAL_FUNC(folderview_selected), folderview);
1969                 gtk_ctree_select(GTK_CTREE(widget), node);
1970                 gtk_signal_handler_unblock_by_func
1971                         (GTK_OBJECT(widget),
1972                          GTK_SIGNAL_FUNC(folderview_selected), folderview);
1973                 gdk_drag_status(context, 
1974                                         (context->actions == GDK_ACTION_COPY ?
1975                                         GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
1976         } else {
1977                 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
1978                 gdk_drag_status(context, 0, time);
1979         }
1980
1981         return acceptable;
1982 }
1983
1984 static void folderview_drag_leave_cb(GtkWidget      *widget,
1985                                      GdkDragContext *context,
1986                                      guint           time,
1987                                      FolderView     *folderview)
1988 {
1989         drag_state_stop(folderview);
1990         gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
1991 }
1992
1993 static void folderview_drag_received_cb(GtkWidget        *widget,
1994                                         GdkDragContext   *drag_context,
1995                                         gint              x,
1996                                         gint              y,
1997                                         GtkSelectionData *data,
1998                                         guint             info,
1999                                         guint             time,
2000                                         FolderView       *folderview)
2001 {
2002         gint row, column;
2003         FolderItem *item, *src_item;
2004         GtkCTreeNode *node;
2005
2006         drag_state_stop(folderview);
2007         if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2008                 /* comes from summaryview */
2009                 if (gtk_clist_get_selection_info
2010                         (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2011                         return;
2012
2013                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2014                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2015                 src_item = folderview->summaryview->folder_item;
2016                 
2017                 /* re-check (due to acceptable possibly set for folder moves */
2018                 if (!(item && item->folder && item->path &&
2019                       src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2020                         return;
2021                 }
2022                 if (item && src_item) {
2023                         switch (drag_context->action) {
2024                         case GDK_ACTION_COPY:
2025                                 summary_copy_selected_to(folderview->summaryview, item);
2026                                 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2027                                 break;
2028                         case GDK_ACTION_MOVE:
2029                         case GDK_ACTION_DEFAULT:
2030                         default:
2031                                 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2032                                         summary_copy_selected_to(folderview->summaryview, item);
2033                                 else
2034                                         summary_move_selected_to(folderview->summaryview, item);
2035                                 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2036                         }
2037                 } else
2038                         gtk_drag_finish(drag_context, FALSE, FALSE, time);
2039         } else {
2040                 /* comes from folderview */
2041                 char *source;
2042                 
2043                 source = data->data + 17;
2044                 if (gtk_clist_get_selection_info
2045                     (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2046                     || *source == 0) {
2047                         gtk_drag_finish(drag_context, FALSE, FALSE, time);                      
2048                         return;
2049                 }
2050                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2051                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2052                 src_item = folder_find_item_from_identifier(source);
2053
2054                 if (!item || !src_item || src_item->stype != F_NORMAL) {
2055                         gtk_drag_finish(drag_context, FALSE, FALSE, time);                      
2056                         return;
2057                 }
2058
2059                 folderview_move_folder(folderview, src_item, item);
2060                 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2061         }
2062         folderview->nodes_to_recollapse = NULL;
2063 }
2064
2065 static void folderview_drag_end_cb(GtkWidget        *widget, 
2066                                    GdkDragContext   *drag_context,
2067                                    FolderView       *folderview)
2068 {
2069         drag_state_stop(folderview);
2070         g_slist_free(folderview->nodes_to_recollapse);
2071         folderview->nodes_to_recollapse = NULL;
2072 }
2073
2074 FolderItem *folderview_get_selected(FolderView *folderview)
2075 {
2076         return (FolderItem *) gtk_ctree_node_get_row_data(
2077                 GTK_CTREE(folderview->ctree), folderview->selected);
2078 }
2079
2080 void folderview_register_popup(FolderViewPopup *fpopup)
2081 {
2082         GList *folderviews;
2083
2084         for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2085                 FolderView *folderview = folderviews->data;
2086                 GtkItemFactory *factory;
2087
2088                 factory = create_ifactory(folderview, fpopup);
2089                 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2090         }       
2091         g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2092 }
2093
2094 void folderview_unregister_popup(FolderViewPopup *fpopup)
2095 {
2096         GList *folderviews;
2097
2098         for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2099                 FolderView *folderview = folderviews->data;
2100
2101                 g_hash_table_remove(folderview->popups, fpopup->klass);
2102         }       
2103         g_hash_table_remove(folderview_popups, fpopup->klass);
2104 }