2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkitemfactory.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"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
69 #define COL_FOLDER_WIDTH 150
70 #define COL_NUM_WIDTH 32
72 static GList *folderview_list = NULL;
74 static GtkStyle *normal_style;
75 static GtkStyle *normal_color_style;
76 static GtkStyle *bold_style;
77 static GtkStyle *bold_color_style;
78 static GtkStyle *bold_tgtfold_style;
80 static GdkPixmap *inboxxpm;
81 static GdkBitmap *inboxxpmmask;
82 static GdkPixmap *inboxhrmxpm;
83 static GdkBitmap *inboxhrmxpmmask;
84 static GdkPixmap *inboxopenxpm;
85 static GdkBitmap *inboxopenxpmmask;
86 static GdkPixmap *inboxopenhrmxpm;
87 static GdkBitmap *inboxopenhrmxpmmask;
88 static GdkPixmap *outboxxpm;
89 static GdkBitmap *outboxxpmmask;
90 static GdkPixmap *outboxhrmxpm;
91 static GdkBitmap *outboxhrmxpmmask;
92 static GdkPixmap *outboxopenxpm;
93 static GdkBitmap *outboxopenxpmmask;
94 static GdkPixmap *outboxopenhrmxpm;
95 static GdkBitmap *outboxopenhrmxpmmask;
96 static GdkPixmap *folderxpm;
97 static GdkBitmap *folderxpmmask;
98 static GdkPixmap *folderhrmxpm;
99 static GdkBitmap *folderhrmxpmmask;
100 static GdkPixmap *folderopenxpm;
101 static GdkBitmap *folderopenxpmmask;
102 static GdkPixmap *folderopenhrmxpm;
103 static GdkBitmap *folderopenhrmxpmmask;
104 static GdkPixmap *trashopenxpm;
105 static GdkBitmap *trashopenxpmmask;
106 static GdkPixmap *trashopenhrmxpm;
107 static GdkBitmap *trashopenhrmxpmmask;
108 static GdkPixmap *trashxpm;
109 static GdkBitmap *trashxpmmask;
110 static GdkPixmap *trashhrmxpm;
111 static GdkBitmap *trashhrmxpmmask;
112 static GdkPixmap *queuexpm;
113 static GdkBitmap *queuexpmmask;
114 static GdkPixmap *queuehrmxpm;
115 static GdkBitmap *queuehrmxpmmask;
116 static GdkPixmap *queueopenxpm;
117 static GdkBitmap *queueopenxpmmask;
118 static GdkPixmap *queueopenhrmxpm;
119 static GdkBitmap *queueopenhrmxpmmask;
120 static GdkPixmap *draftsxpm;
121 static GdkBitmap *draftsxpmmask;
122 static GdkPixmap *draftsopenxpm;
123 static GdkBitmap *draftsopenxpmmask;
124 static GdkPixmap *noselectxpm;
125 static GdkBitmap *noselectxpmmask;
127 static GdkPixmap *m_inboxxpm;
128 static GdkBitmap *m_inboxxpmmask;
129 static GdkPixmap *m_inboxhrmxpm;
130 static GdkBitmap *m_inboxhrmxpmmask;
131 static GdkPixmap *m_inboxopenxpm;
132 static GdkBitmap *m_inboxopenxpmmask;
133 static GdkPixmap *m_inboxopenhrmxpm;
134 static GdkBitmap *m_inboxopenhrmxpmmask;
135 static GdkPixmap *m_outboxxpm;
136 static GdkBitmap *m_outboxxpmmask;
137 static GdkPixmap *m_outboxhrmxpm;
138 static GdkBitmap *m_outboxhrmxpmmask;
139 static GdkPixmap *m_outboxopenxpm;
140 static GdkBitmap *m_outboxopenxpmmask;
141 static GdkPixmap *m_outboxopenhrmxpm;
142 static GdkBitmap *m_outboxopenhrmxpmmask;
143 static GdkPixmap *m_folderxpm;
144 static GdkBitmap *m_folderxpmmask;
145 static GdkPixmap *m_folderhrmxpm;
146 static GdkBitmap *m_folderhrmxpmmask;
147 static GdkPixmap *m_folderopenxpm;
148 static GdkBitmap *m_folderopenxpmmask;
149 static GdkPixmap *m_folderopenhrmxpm;
150 static GdkBitmap *m_folderopenhrmxpmmask;
151 static GdkPixmap *m_trashopenxpm;
152 static GdkBitmap *m_trashopenxpmmask;
153 static GdkPixmap *m_trashopenhrmxpm;
154 static GdkBitmap *m_trashopenhrmxpmmask;
155 static GdkPixmap *m_trashxpm;
156 static GdkBitmap *m_trashxpmmask;
157 static GdkPixmap *m_trashhrmxpm;
158 static GdkBitmap *m_trashhrmxpmmask;
159 static GdkPixmap *m_queuexpm;
160 static GdkBitmap *m_queuexpmmask;
161 static GdkPixmap *m_queuehrmxpm;
162 static GdkBitmap *m_queuehrmxpmmask;
163 static GdkPixmap *m_queueopenxpm;
164 static GdkBitmap *m_queueopenxpmmask;
165 static GdkPixmap *m_queueopenhrmxpm;
166 static GdkBitmap *m_queueopenhrmxpmmask;
167 static GdkPixmap *m_draftsxpm;
168 static GdkBitmap *m_draftsxpmmask;
169 static GdkPixmap *m_draftsopenxpm;
170 static GdkBitmap *m_draftsopenxpmmask;
172 static GdkPixmap *newxpm;
173 static GdkBitmap *newxpmmask;
174 static GdkPixmap *unreadxpm;
175 static GdkBitmap *unreadxpmmask;
176 static GdkPixmap *readxpm;
177 static GdkBitmap *readxpmmask;
180 static void folderview_select_node (FolderView *folderview,
182 static void folderview_set_folders (FolderView *folderview);
183 static void folderview_sort_folders (FolderView *folderview,
186 static void folderview_append_folder (FolderView *folderview,
188 static void folderview_update_node (FolderView *folderview,
191 static gint folderview_clist_compare (GtkCList *clist,
195 /* callback functions */
196 static gboolean folderview_button_pressed (GtkWidget *ctree,
197 GdkEventButton *event,
198 FolderView *folderview);
199 static gboolean folderview_button_released (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_key_pressed (GtkWidget *widget,
204 FolderView *folderview);
205 static void folderview_selected (GtkCTree *ctree,
208 FolderView *folderview);
209 static void folderview_tree_expanded (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_collapsed (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_popup_close (GtkMenuShell *menu_shell,
216 FolderView *folderview);
217 static void folderview_col_resized (GtkCList *clist,
220 FolderView *folderview);
222 static void mark_all_read_cb (FolderView *folderview,
226 static void folderview_empty_trash_cb (FolderView *folderview,
230 static void folderview_send_queue_cb (FolderView *folderview,
234 static void folderview_search_cb (FolderView *folderview,
238 static void folderview_property_cb (FolderView *folderview,
242 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
243 GdkDragContext *context,
247 FolderView *folderview);
248 static void folderview_drag_leave_cb (GtkWidget *widget,
249 GdkDragContext *context,
251 FolderView *folderview);
252 static void folderview_drag_received_cb (GtkWidget *widget,
253 GdkDragContext *drag_context,
256 GtkSelectionData *data,
259 FolderView *folderview);
260 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
261 FolderView *folderview);
262 static void folderview_drag_data_get (GtkWidget *widget,
263 GdkDragContext *drag_context,
264 GtkSelectionData *selection_data,
267 FolderView *folderview);
268 static void folderview_drag_end_cb (GtkWidget *widget,
269 GdkDragContext *drag_context,
270 FolderView *folderview);
272 void folderview_create_folder_node (FolderView *folderview,
274 gboolean folderview_update_folder (gpointer source,
276 gboolean folderview_update_item_claws (gpointer source,
278 static void folderview_processing_cb(FolderView *folderview, guint action,
281 GHashTable *folderview_popups;
283 static GtkItemFactoryEntry folderview_common_popup_entries[] =
285 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
286 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
287 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
288 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
291 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
292 {N_("/------trashsep"), NULL, NULL, 0, "<Separator>"},
293 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
296 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
297 {N_("/------queuesep"), NULL, NULL, 0, "<Separator>"},
298 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
302 GtkTargetEntry folderview_drag_types[] =
304 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
305 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
308 void folderview_initialize(void)
310 FolderViewPopup *fpopup;
312 GSList *entries = NULL;
314 fpopup = g_new0(FolderViewPopup, 1);
316 n_entries = sizeof(folderview_common_popup_entries) /
317 sizeof(folderview_common_popup_entries[0]);
318 for (i = 0; i < n_entries; i++)
319 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
321 fpopup->klass = "common";
322 fpopup->path = "<CommonFolder>";
323 fpopup->entries = entries;
324 fpopup->set_sensitivity = NULL;
326 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
327 g_hash_table_insert(folderview_popups, "common", fpopup);
330 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
333 GtkItemFactory *factory;
334 FolderViewPopup *fpopup_common;
337 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
338 gtk_item_factory_set_translate_func(factory, menu_translate,
341 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
342 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
344 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
345 if (fpopup_common != fpopup)
346 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
347 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
349 popup = gtk_item_factory_get_widget(factory, fpopup->path);
350 g_signal_connect(G_OBJECT(popup), "selection_done",
351 G_CALLBACK(folderview_popup_close),
357 static void create_ifactories(gpointer key, gpointer value, gpointer data)
359 FolderView *folderview = data;
360 FolderViewPopup *fpopup = value;
361 GtkItemFactory *factory;
363 factory = create_ifactory(folderview, fpopup);
364 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
367 static void folderview_column_set_titles(FolderView *folderview)
369 GtkWidget *ctree = folderview->ctree;
370 GtkWidget *label_new;
371 GtkWidget *label_unread;
372 GtkWidget *label_total;
374 GtkWidget *hbox_unread;
375 GtkWidget *hbox_total;
376 gint *col_pos = folderview->col_pos;
378 debug_print("setting titles...\n");
379 gtk_widget_realize(folderview->ctree);
380 gtk_widget_show_all(folderview->scrolledwin);
382 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
383 * instead text (text overflows making them unreadable and ugly) */
384 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
385 &newxpm, &newxpmmask);
386 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
387 &unreadxpm, &unreadxpmmask);
388 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
389 &readxpm, &readxpmmask);
391 label_new = gtk_pixmap_new(newxpm, newxpmmask);
392 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
393 label_total = gtk_pixmap_new(readxpm, readxpmmask);
395 hbox_new = gtk_hbox_new(FALSE, 4);
396 hbox_unread = gtk_hbox_new(FALSE, 4);
397 hbox_total = gtk_hbox_new(FALSE, 4);
400 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
401 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
402 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
403 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
404 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
405 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
407 gtk_widget_show_all(hbox_new);
408 gtk_widget_show_all(hbox_unread);
409 gtk_widget_show_all(hbox_total);
411 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
412 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
413 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
416 GtkWidget *folderview_ctree_create(FolderView *folderview)
420 FolderColumnState *col_state;
421 FolderColumnType type;
422 gchar *titles[N_FOLDER_COLS];
424 GtkWidget *scrolledwin = folderview->scrolledwin;
426 debug_print("creating tree...\n");
427 memset(titles, 0, sizeof(titles));
429 col_state = prefs_folder_column_get_config();
430 memset(titles, 0, sizeof(titles));
432 col_pos = folderview->col_pos;
434 for (i = 0; i < N_FOLDER_COLS; i++) {
435 folderview->col_state[i] = col_state[i];
436 type = col_state[i].type;
440 titles[col_pos[F_COL_FOLDER]] = _("Folder");
441 titles[col_pos[F_COL_NEW]] = _("New");
442 titles[col_pos[F_COL_UNREAD]] = _("Unread");
443 /* TRANSLATORS: This in Number sign in American style */
444 titles[col_pos[F_COL_TOTAL]] = _("#");
446 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
449 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
450 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
452 gtk_clist_set_column_justification(GTK_CLIST(ctree),
453 col_pos[F_COL_UNREAD],
455 gtk_clist_set_column_justification(GTK_CLIST(ctree),
456 col_pos[F_COL_TOTAL],
458 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
459 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
460 GTK_CTREE_EXPANDER_SQUARE);
461 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
462 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
464 /* don't let title buttons take key focus */
465 for (i = 0; i < N_FOLDER_COLS; i++) {
466 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
468 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
469 prefs_common.folder_col_size[i]);
470 gtk_clist_set_column_visibility
471 (GTK_CLIST(ctree), i, col_state[i].visible);
474 g_signal_connect(G_OBJECT(ctree), "key_press_event",
475 G_CALLBACK(folderview_key_pressed),
477 g_signal_connect(G_OBJECT(ctree), "button_press_event",
478 G_CALLBACK(folderview_button_pressed),
480 g_signal_connect(G_OBJECT(ctree), "button_release_event",
481 G_CALLBACK(folderview_button_released),
483 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
484 G_CALLBACK(folderview_selected), folderview);
485 g_signal_connect(G_OBJECT(ctree), "start_drag",
486 G_CALLBACK(folderview_start_drag), folderview);
487 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
488 G_CALLBACK(folderview_drag_data_get),
491 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
492 G_CALLBACK(folderview_tree_expanded),
494 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
495 G_CALLBACK(folderview_tree_collapsed),
498 g_signal_connect(G_OBJECT(ctree), "resize_column",
499 G_CALLBACK(folderview_col_resized),
503 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
504 folderview_drag_types, 2,
505 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
506 g_signal_connect(G_OBJECT(ctree), "drag_motion",
507 G_CALLBACK(folderview_drag_motion_cb),
509 g_signal_connect(G_OBJECT(ctree), "drag_leave",
510 G_CALLBACK(folderview_drag_leave_cb),
512 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
513 G_CALLBACK(folderview_drag_received_cb),
515 g_signal_connect(G_OBJECT(ctree), "drag_end",
516 G_CALLBACK(folderview_drag_end_cb),
519 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
524 void folderview_set_column_order(FolderView *folderview)
527 FolderItem *item = folderview_get_selected_item(folderview);
528 GtkWidget *scrolledwin = folderview->scrolledwin;
530 debug_print("recreating tree...\n");
531 gtk_widget_destroy(folderview->ctree);
533 folderview->ctree = ctree = folderview_ctree_create(folderview);
534 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
535 GTK_CLIST(ctree)->hadjustment);
536 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
537 GTK_CLIST(ctree)->vadjustment);
538 gtk_widget_show(ctree);
540 folderview_set(folderview);
541 folderview_column_set_titles(folderview);
543 folderview_select(folderview,item);
546 FolderView *folderview_create(void)
548 FolderView *folderview;
549 GtkWidget *scrolledwin;
552 debug_print("Creating folder view...\n");
553 folderview = g_new0(FolderView, 1);
555 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
556 gtk_scrolled_window_set_policy
557 (GTK_SCROLLED_WINDOW(scrolledwin),
558 GTK_POLICY_AUTOMATIC,
559 prefs_common.folderview_vscrollbar_policy);
560 gtk_widget_set_size_request(scrolledwin,
561 prefs_common.folderview_width,
562 prefs_common.folderview_height);
564 folderview->scrolledwin = scrolledwin;
565 ctree = folderview_ctree_create(folderview);
567 /* create popup factories */
568 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
569 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
571 folderview->ctree = ctree;
573 folderview->folder_update_callback_id =
574 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
575 folderview->folder_item_update_callback_id =
576 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
578 gtk_widget_show_all(scrolledwin);
580 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
581 folderview_list = g_list_append(folderview_list, folderview);
586 void folderview_init(FolderView *folderview)
588 GtkWidget *ctree = folderview->ctree;
591 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
592 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
593 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
594 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
595 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
596 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
597 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
598 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
599 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
600 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
601 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
602 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
603 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
604 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
605 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
606 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
607 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
608 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
609 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
610 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
611 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
612 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
613 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
615 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
616 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
617 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
618 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
619 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
620 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
621 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
622 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
623 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
639 PangoFontDescription *font_desc;
640 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
641 font_desc = pango_font_description_from_string(NORMAL_FONT);
643 if (normal_style->font_desc)
644 pango_font_description_free
645 (normal_style->font_desc);
646 normal_style->font_desc = font_desc;
648 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
649 normal_color_style = gtk_style_copy(normal_style);
650 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
652 gtk_widget_set_style(ctree, normal_style);
656 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
657 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
658 pango_font_description_set_weight
659 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
660 bold_color_style = gtk_style_copy(bold_style);
661 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
663 bold_tgtfold_style = gtk_style_copy(bold_style);
664 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
668 void folderview_set(FolderView *folderview)
670 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
671 MainWindow *mainwin = folderview->mainwin;
676 debug_print("Setting folder info...\n");
677 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
679 main_window_cursor_wait(mainwin);
681 folderview->selected = NULL;
682 folderview->opened = NULL;
684 gtk_clist_freeze(GTK_CLIST(ctree));
685 gtk_clist_clear(GTK_CLIST(ctree));
686 gtk_clist_thaw(GTK_CLIST(ctree));
687 gtk_clist_freeze(GTK_CLIST(ctree));
689 folderview_set_folders(folderview);
691 gtk_clist_thaw(GTK_CLIST(ctree));
692 main_window_cursor_normal(mainwin);
693 STATUSBAR_POP(mainwin);
696 void folderview_set_all(void)
700 for (list = folderview_list; list != NULL; list = list->next)
701 folderview_set((FolderView *)list->data);
704 void folderview_select(FolderView *folderview, FolderItem *item)
706 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
708 GtkCTreeNode *old_selected = folderview->selected;
712 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
713 if (node) folderview_select_node(folderview, node);
715 if (old_selected != node)
716 folder_update_op_count();
719 static void mark_all_read_cb(FolderView *folderview, guint action,
725 item = folderview_get_selected_item(folderview);
729 if (folderview->summaryview->folder_item != item
730 && prefs_common.ask_mark_all_read) {
731 val = alertpanel_full(_("Mark all as read"),
732 _("Do you really want to mark all mails in this "
733 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
734 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
736 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
738 else if (val & G_ALERTDISABLE)
739 prefs_common.ask_mark_all_read = FALSE;
742 summary_lock(folderview->summaryview);
743 folder_item_update_freeze();
744 if (folderview->summaryview->folder_item == item)
745 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
746 folderutils_mark_all_read(item);
747 if (folderview->summaryview->folder_item == item)
748 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
749 folder_item_update_thaw();
750 summary_unlock(folderview->summaryview);
753 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
755 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
757 g_return_if_fail(node != NULL);
759 folderview->open_folder = TRUE;
760 gtkut_ctree_set_focus_row(ctree, node);
761 gtk_ctree_select(ctree, node);
762 if (folderview->summaryview->folder_item &&
763 folderview->summaryview->folder_item->total_msgs > 0)
764 gtk_widget_grab_focus(folderview->summaryview->ctree);
766 gtk_widget_grab_focus(folderview->ctree);
768 gtkut_ctree_expand_parent_all(ctree, node);
771 void folderview_unselect(FolderView *folderview)
773 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
775 (GTK_CTREE(folderview->ctree), folderview->opened);
777 folderview->selected = folderview->opened = NULL;
780 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
786 node = gtkut_ctree_node_next(ctree, node);
788 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
790 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
791 item = gtk_ctree_node_get_row_data(ctree, node);
792 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
799 void folderview_select_next_marked(FolderView *folderview)
801 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
802 GtkCTreeNode *node = NULL;
803 SelectOnEntry last_sel = prefs_common.select_on_entry;
804 prefs_common.select_on_entry = SELECTONENTRY_MNU;
806 if ((node = folderview_find_next_marked(ctree, folderview->opened))
808 folderview_select_node(folderview, node);
809 prefs_common.select_on_entry = last_sel;
813 if (!folderview->opened ||
814 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
815 prefs_common.select_on_entry = last_sel;
818 /* search again from the first node */
819 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
820 folderview_select_node(folderview, node);
821 prefs_common.select_on_entry = last_sel;
824 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
830 node = gtkut_ctree_node_next(ctree, node);
832 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
834 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
835 item = gtk_ctree_node_get_row_data(ctree, node);
836 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
843 void folderview_select_next_unread(FolderView *folderview)
845 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
846 GtkCTreeNode *node = NULL;
847 SelectOnEntry last_sel = prefs_common.select_on_entry;
848 prefs_common.select_on_entry = SELECTONENTRY_UNM;
850 if ((node = folderview_find_next_unread(ctree, folderview->opened))
852 folderview_select_node(folderview, node);
853 prefs_common.select_on_entry = last_sel;
857 if (!folderview->opened ||
858 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
859 prefs_common.select_on_entry = last_sel;
862 /* search again from the first node */
863 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
864 folderview_select_node(folderview, node);
866 prefs_common.select_on_entry = last_sel;
870 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
876 node = gtkut_ctree_node_next(ctree, node);
878 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
880 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
881 item = gtk_ctree_node_get_row_data(ctree, node);
882 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
889 void folderview_select_next_new(FolderView *folderview)
891 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
892 GtkCTreeNode *node = NULL;
893 SelectOnEntry last_sel = prefs_common.select_on_entry;
894 prefs_common.select_on_entry = SELECTONENTRY_NUM;
896 if ((node = folderview_find_next_new(ctree, folderview->opened))
898 folderview_select_node(folderview, node);
899 prefs_common.select_on_entry = last_sel;
903 if (!folderview->opened ||
904 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
905 prefs_common.select_on_entry = last_sel;
908 /* search again from the first node */
909 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
910 folderview_select_node(folderview, node);
911 prefs_common.select_on_entry = last_sel;
914 FolderItem *folderview_get_selected_item(FolderView *folderview)
916 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
918 if (!folderview->selected) return NULL;
919 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
922 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
924 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
925 static GtkCTreeNode *prev_row = NULL;
927 gint new, unread, total;
928 gchar *new_str, *unread_str, *total_str;
929 gint *col_pos = folderview->col_pos;
933 item = gtk_ctree_node_get_row_data(ctree, row);
936 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
937 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
938 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
940 unread = atoi(unread_str);
941 total = atoi(total_str);
945 folderview_update_node(folderview, row);
948 void folderview_append_item(FolderItem *item)
952 g_return_if_fail(item != NULL);
953 g_return_if_fail(item->folder != NULL);
954 if (folder_item_parent(item)) return;
956 for (list = folderview_list; list != NULL; list = list->next) {
957 FolderView *folderview = (FolderView *)list->data;
958 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
959 GtkCTreeNode *node, *child;
960 gint *col_pos = folderview->col_pos;
962 node = gtk_ctree_find_by_row_data(ctree, NULL,
963 folder_item_parent(item));
965 child = gtk_ctree_find_by_row_data(ctree, node, item);
967 gchar *text[N_FOLDER_COLS] =
968 {NULL, "0", "0", "0"};
970 gtk_clist_freeze(GTK_CLIST(ctree));
972 text[col_pos[F_COL_FOLDER]] = item->name;
973 child = gtk_sctree_insert_node
974 (ctree, node, NULL, text,
976 folderxpm, folderxpmmask,
977 folderopenxpm, folderopenxpmmask,
979 gtk_ctree_node_set_row_data(ctree, child, item);
980 gtk_ctree_expand(ctree, node);
981 folderview_update_node(folderview, child);
982 folderview_sort_folders(folderview, node,
985 gtk_clist_thaw(GTK_CLIST(ctree));
991 static void folderview_set_folders(FolderView *folderview)
994 #ifndef HAVE_LIBETPAN
995 static gboolean missing_imap_warning = TRUE;
997 list = folder_get_list();
999 for (; list != NULL; list = list->next) {
1000 #ifndef HAVE_LIBETPAN
1001 if ((FOLDER(list->data))
1002 && (FOLDER(list->data))->klass
1003 && (FOLDER(list->data))->klass->type == F_IMAP
1004 && missing_imap_warning) {
1005 missing_imap_warning = FALSE;
1007 _("You have one or more IMAP accounts "
1008 "defined. However this version of "
1009 "Sylpheed-Claws has been built without "
1010 "IMAP support; your IMAP account(s) are "
1012 "You probably need to "
1013 "install libetpan and recompile "
1014 "Sylpheed-Claws."));
1017 folderview_append_folder(folderview, FOLDER(list->data));
1021 static gchar *get_scan_str(FolderItem *item)
1024 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1025 item->folder->name, G_DIR_SEPARATOR,
1028 return g_strdup_printf(_("Scanning folder %s ..."),
1029 item->folder->name);
1031 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1035 for (list = folderview_list; list != NULL; list = list->next) {
1036 FolderView *folderview = (FolderView *)list->data;
1037 MainWindow *mainwin = folderview->mainwin;
1038 gchar *str = get_scan_str(item);
1040 STATUSBAR_PUSH(mainwin, str);
1041 STATUSBAR_POP(mainwin);
1046 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1050 g_return_if_fail(folder != NULL);
1052 if (!folder->klass->scan_tree) return;
1055 alertpanel_full(_("Rebuild folder tree"),
1056 _("Rebuilding the folder tree will remove "
1057 "local caches. Do you want to continue?"),
1058 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1059 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1060 != G_ALERTALTERNATE) {
1066 window = label_window_create(_("Rebuilding folder tree..."));
1068 window = label_window_create(_("Scanning folder tree..."));
1070 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1071 folder_scan_tree(folder, rebuild);
1072 folder_set_ui_func(folder, NULL, NULL);
1074 folderview_set_all();
1076 gtk_widget_destroy(window);
1080 /** folderview_check_new()
1081 * Scan and update the folder and return the
1082 * count the number of new messages since last check.
1083 * \param folder the folder to check for new messages
1084 * \return the number of new messages since last check
1086 gint folderview_check_new(Folder *folder)
1090 FolderView *folderview;
1094 gint former_new_msgs = 0;
1095 gint former_new = 0, former_unread = 0, former_total;
1097 for (list = folderview_list; list != NULL; list = list->next) {
1098 folderview = (FolderView *)list->data;
1099 ctree = GTK_CTREE(folderview->ctree);
1102 main_window_lock(folderview->mainwin);
1104 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1105 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1107 item = gtk_ctree_node_get_row_data(ctree, node);
1108 if (!item || !item->path || !item->folder) continue;
1109 if (item->no_select) continue;
1110 if (folder && folder != item->folder) continue;
1111 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1112 if (!item->prefs->newmailcheck) continue;
1113 if (item->processing_pending == TRUE) {
1114 debug_print("skipping %s, processing pending\n",
1115 item->path ? item->path : item->name);
1119 str = get_scan_str(item);
1121 STATUSBAR_PUSH(folderview->mainwin, str);
1125 folderview_scan_tree_func(item->folder, item, NULL);
1126 former_new = item->new_msgs;
1127 former_unread = item->unread_msgs;
1128 former_total = item->total_msgs;
1130 if (item->folder->klass->scan_required &&
1131 (item->folder->klass->scan_required(item->folder, item) ||
1132 item->folder->inbox == item ||
1133 item->opened == TRUE ||
1134 item->processing_pending == TRUE)) {
1135 if (folder_item_scan(item) < 0) {
1136 summaryview_unlock(folderview->summaryview, item);
1137 if (folder && !FOLDER_IS_LOCAL(folder)) {
1138 STATUSBAR_POP(folderview->mainwin);
1142 } else if (!item->folder->klass->scan_required) {
1143 if (folder_item_scan(item) < 0) {
1144 summaryview_unlock(folderview->summaryview, item);
1145 if (folder && !FOLDER_IS_LOCAL(folder)) {
1146 STATUSBAR_POP(folderview->mainwin);
1151 if (former_new != item->new_msgs ||
1152 former_unread != item->unread_msgs ||
1153 former_total != item->total_msgs)
1154 folderview_update_node(folderview, node);
1156 new_msgs += item->new_msgs;
1157 former_new_msgs += former_new;
1158 STATUSBAR_POP(folderview->mainwin);
1161 main_window_unlock(folderview->mainwin);
1165 folder_write_list();
1166 /* Number of new messages since last check is the just the difference
1167 * between former_new_msgs and new_msgs. If new_msgs is less than
1168 * former_new_msgs, that would mean another session accessed the folder
1169 * and the result is not well defined.
1171 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1175 void folderview_check_new_all(void)
1179 FolderView *folderview;
1181 folderview = (FolderView *)folderview_list->data;
1184 main_window_lock(folderview->mainwin);
1185 window = label_window_create
1186 (_("Checking for new messages in all folders..."));
1188 list = folder_get_list();
1189 for (; list != NULL; list = list->next) {
1190 Folder *folder = list->data;
1192 folderview_check_new(folder);
1195 folder_write_list();
1196 folderview_set_all();
1198 gtk_widget_destroy(window);
1199 main_window_unlock(folderview->mainwin);
1203 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1209 if (!item || !item->folder || !item->folder->node)
1212 node = item->folder->node;
1214 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1215 node = node->children;
1218 (item->new_msgs > 0 ||
1219 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1223 while (node != NULL) {
1224 if (node && node->data) {
1225 FolderItem *next_item = (FolderItem*) node->data;
1227 if (folderview_have_new_children_sub(folderview,
1236 static gboolean folderview_have_new_children(FolderView *folderview,
1239 return folderview_have_new_children_sub(folderview, item, FALSE);
1242 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1248 if (!item || !item->folder || !item->folder->node)
1251 node = item->folder->node;
1253 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1254 node = node->children;
1257 (item->unread_msgs > 0 ||
1258 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1262 while (node != NULL) {
1263 if (node && node->data) {
1264 FolderItem *next_item = (FolderItem*) node->data;
1266 if (folderview_have_unread_children_sub(folderview,
1276 static gboolean folderview_have_unread_children(FolderView *folderview,
1279 return folderview_have_unread_children_sub(folderview, item, FALSE);
1282 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1288 if (!item || !item->folder || !item->folder->node)
1291 node = item->folder->node;
1293 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1294 node = node->children;
1296 if (in_sub && item->search_match){
1300 while (node != NULL) {
1301 if (node && node->data) {
1302 FolderItem *next_item = (FolderItem*) node->data;
1304 if (folderview_have_matching_children_sub(folderview,
1314 static gboolean folderview_have_matching_children(FolderView *folderview,
1317 return folderview_have_matching_children_sub(folderview, item, FALSE);
1320 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1326 if (!item || !item->folder || !item->folder->node)
1329 node = item->folder->node;
1331 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1332 node = node->children;
1334 if (item->marked_msgs != 0) {
1338 while (node != NULL) {
1339 if (node && node->data) {
1340 FolderItem *next_item = (FolderItem*) node->data;
1342 if (folderview_have_marked_children_sub(folderview,
1351 static gboolean folderview_have_marked_children(FolderView *folderview,
1354 return folderview_have_marked_children_sub(folderview, item, FALSE);
1357 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1359 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1360 GtkStyle *style = NULL;
1361 GtkStyle *color_style = NULL;
1363 GdkPixmap *xpm, *openxpm;
1364 GdkBitmap *mask, *openmask;
1365 static GdkPixmap *searchicon;
1366 static GdkBitmap *searchmask;
1367 gboolean mark = FALSE;
1370 gboolean add_unread_mark;
1371 gboolean add_sub_match_mark;
1372 gboolean use_bold, use_color;
1373 gint *col_pos = folderview->col_pos;
1374 SpecialFolderItemType stype;
1376 item = gtk_ctree_node_get_row_data(ctree, node);
1377 g_return_if_fail(item != NULL);
1379 if (!GTK_CTREE_ROW(node)->expanded)
1380 mark = folderview_have_marked_children(folderview, item);
1382 mark = (item->marked_msgs != 0);
1384 stype = item->stype;
1385 if (stype == F_NORMAL) {
1386 if (folder_has_parent_of_type(item, F_TRASH))
1388 else if (folder_has_parent_of_type(item, F_DRAFT))
1390 else if (folder_has_parent_of_type(item, F_OUTBOX))
1392 else if (folder_has_parent_of_type(item, F_QUEUE))
1397 if (item->hide_read_msgs) {
1398 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1399 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1400 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1401 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1403 xpm = mark?m_inboxxpm:inboxxpm;
1404 mask = mark?m_inboxxpmmask:inboxxpmmask;
1405 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1406 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1410 if (item->hide_read_msgs) {
1411 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1412 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1413 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1414 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1416 xpm = mark?m_outboxxpm:outboxxpm;
1417 mask = mark?m_outboxxpmmask:outboxxpmmask;
1418 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1419 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1423 if (item->hide_read_msgs) {
1424 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1425 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1426 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1427 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1429 xpm = mark?m_queuexpm:queuexpm;
1430 mask = mark?m_queuexpmmask:queuexpmmask;
1431 openxpm = mark?m_queueopenxpm:queueopenxpm;
1432 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1436 if (item->hide_read_msgs) {
1437 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1438 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1439 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1440 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1442 xpm = mark?m_trashxpm:trashxpm;
1443 mask = mark?m_trashxpmmask:trashxpmmask;
1444 openxpm = mark?m_trashopenxpm:trashopenxpm;
1445 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1449 xpm = mark?m_draftsxpm:draftsxpm;
1450 mask = mark?m_draftsxpmmask:draftsxpmmask;
1451 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1452 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1455 if (item->hide_read_msgs) {
1456 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1457 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1458 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1459 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1461 xpm = mark?m_folderxpm:folderxpm;
1462 mask = mark?m_folderxpmmask:folderxpmmask;
1463 openxpm = mark?m_folderopenxpm:folderopenxpm;
1464 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1468 if (item->no_select) {
1469 xpm = openxpm = noselectxpm;
1470 mask = openmask = noselectxpmmask;
1473 name = folder_item_get_name(item);
1475 if (!GTK_CTREE_ROW(node)->expanded) {
1476 add_unread_mark = folderview_have_unread_children(
1478 add_sub_match_mark = folderview_have_matching_children(
1481 add_unread_mark = FALSE;
1482 add_sub_match_mark = FALSE;
1485 if (item->search_match) {
1487 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1488 &searchicon, &searchmask);
1490 xpm = openxpm = searchicon;
1491 mask = openmask = searchmask;
1494 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1495 prefs_common.display_folder_unread) {
1496 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1497 add_unread_mark ? "+" : "");
1498 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1499 xpm, mask, openxpm, openmask,
1500 FALSE, GTK_CTREE_ROW(node)->expanded);
1502 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1503 prefs_common.display_folder_unread)
1504 || add_sub_match_mark) {
1506 if (item->unread_msgs > 0)
1507 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1508 add_unread_mark || add_sub_match_mark ? "+" : "",
1509 item->unreadmarked_msgs > 0 ? "!":"");
1511 str = g_strdup_printf("%s (+)", name);
1512 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1513 xpm, mask, openxpm, openmask,
1514 FALSE, GTK_CTREE_ROW(node)->expanded);
1517 str = g_strdup_printf("%s%s", name,
1518 item->unreadmarked_msgs > 0 ? " (!)":"");
1520 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1521 xpm, mask, openxpm, openmask,
1522 FALSE, GTK_CTREE_ROW(node)->expanded);
1527 if (!folder_item_parent(item)) {
1528 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1529 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1530 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1532 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1533 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1534 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1537 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1538 folder_has_parent_of_type(item, F_DRAFT) ||
1539 folder_has_parent_of_type(item, F_TRASH)) {
1540 use_bold = use_color = FALSE;
1541 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1542 /* highlight queue folder if there are any messages */
1543 use_bold = use_color = (item->total_msgs > 0);
1545 /* if unread messages exist, print with bold font */
1546 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1548 /* if new messages exist, print with colored letter */
1550 (item->new_msgs > 0) ||
1552 folderview_have_new_children(folderview, item));
1555 gtk_ctree_node_set_foreground(ctree, node, NULL);
1560 if (item->prefs->color > 0 && !use_color) {
1561 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1562 color_style = gtk_style_copy(bold_style);
1563 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1564 style = color_style;
1565 } else if (use_color) {
1566 style = bold_color_style;
1569 if (item->op_count > 0) {
1570 style = bold_tgtfold_style;
1572 } else if (use_color) {
1573 style = normal_color_style;
1574 gtk_ctree_node_set_foreground(ctree, node,
1575 &folderview->color_new);
1576 } else if (item->op_count > 0) {
1577 style = bold_tgtfold_style;
1578 } else if (item->prefs->color > 0) {
1580 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1581 color_style = gtk_style_copy(normal_style);
1582 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1583 style = color_style;
1585 style = normal_style;
1588 gtk_ctree_node_set_row_style(ctree, node, style);
1590 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1591 folderview_update_node(folderview, node);
1594 #if !CLAWS /* keep it here for syncs */
1595 void folderview_update_item(FolderItem *item, gboolean update_summary)
1598 FolderView *folderview;
1602 g_return_if_fail(item != NULL);
1604 for (list = folderview_list; list != NULL; list = list->next) {
1605 folderview = (FolderView *)list->data;
1606 ctree = GTK_CTREE(folderview->ctree);
1608 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1610 folderview_update_node(folderview, node);
1611 if (update_summary && folderview->opened == node)
1612 summary_show(folderview->summaryview,
1619 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1622 FolderView *folderview;
1626 g_return_if_fail(item != NULL);
1628 for (list = folderview_list; list != NULL; list = list->next) {
1629 folderview = (FolderView *)list->data;
1630 ctree = GTK_CTREE(folderview->ctree);
1632 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1634 item->search_match = matches;
1635 folderview_update_node(folderview, node);
1640 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1642 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1643 FolderView *folderview = (FolderView *)data;
1646 g_return_val_if_fail(update_info != NULL, TRUE);
1647 g_return_val_if_fail(update_info->item != NULL, TRUE);
1648 g_return_val_if_fail(folderview != NULL, FALSE);
1650 ctree = GTK_CTREE(folderview->ctree);
1652 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1654 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1655 folderview_update_node(folderview, node);
1656 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1657 summary_show(folderview->summaryview, update_info->item);
1663 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1666 /* CLAWS: share this joy with other hook functions ... */
1667 folder_item_update((FolderItem *)key,
1668 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1671 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1674 FolderItemUpdateFlags flags;
1676 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1678 for (list = folderview_list; list != NULL; list = list->next)
1679 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1680 GINT_TO_POINTER(flags));
1683 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1684 GNode *gnode, GtkCTreeNode *cnode,
1687 FolderView *folderview = (FolderView *)data;
1688 FolderItem *item = FOLDER_ITEM(gnode->data);
1690 g_return_val_if_fail(item != NULL, FALSE);
1692 gtk_ctree_node_set_row_data(ctree, cnode, item);
1693 folderview_update_node(folderview, cnode);
1698 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1701 FolderView *folderview = (FolderView *)data;
1704 if (GTK_CTREE_ROW(node)->children) {
1705 item = gtk_ctree_node_get_row_data(ctree, node);
1706 g_return_if_fail(item != NULL);
1708 if (!item->collapsed)
1709 gtk_ctree_expand(ctree, node);
1711 folderview_update_node(folderview, node);
1715 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1716 GtkCTreeNode *root, GtkCTreeNode **prev)
1719 GtkCTreeNode *node, *parent, *sibling;
1721 node = gtk_ctree_find_by_row_data(ctree, root, item);
1723 g_warning("%s not found.\n", item->path);
1725 parent = GTK_CTREE_ROW(node)->parent;
1726 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1727 sibling = GTK_CTREE_ROW(*prev)->sibling;
1729 sibling = GTK_CTREE_ROW(parent)->children;
1733 tmp = gtk_ctree_node_get_row_data
1735 if (tmp->stype != F_NORMAL)
1736 sibling = GTK_CTREE_ROW(sibling)->sibling;
1740 if (node != sibling)
1741 gtk_ctree_move(ctree, node, parent, sibling);
1748 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1751 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1752 GtkCTreeNode *prev = NULL;
1754 gtk_sctree_sort_recursive(ctree, root);
1756 if (root && GTK_CTREE_ROW(root)->parent) return;
1758 set_special_folder(ctree, folder->inbox, root, &prev);
1759 set_special_folder(ctree, folder->outbox, root, &prev);
1760 set_special_folder(ctree, folder->draft, root, &prev);
1761 set_special_folder(ctree, folder->queue, root, &prev);
1762 set_special_folder(ctree, folder->trash, root, &prev);
1765 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1767 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1770 g_return_if_fail(folder != NULL);
1772 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1773 folderview_gnode_func, folderview);
1774 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1776 folderview_sort_folders(folderview, root, folder);
1779 /* callback functions */
1781 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1782 FolderView *folderview)
1784 GtkCList *clist = GTK_CLIST(ctree);
1785 gint prev_row = -1, row = -1, column = -1;
1788 FolderViewPopup *fpopup;
1789 GtkItemFactory *fpopup_factory;
1791 FolderItem *special_trash = NULL, *special_queue = NULL;
1794 if (!event) return FALSE;
1796 if (event->button == 1 || event->button == 2) {
1797 folderview->open_folder = TRUE;
1799 if (event->type == GDK_2BUTTON_PRESS) {
1800 if (clist->selection) {
1803 node = GTK_CTREE_NODE(clist->selection->data);
1805 gtk_ctree_toggle_expansion(
1813 if (event->button == 2 || event->button == 3) {
1815 if (clist->selection) {
1818 node = GTK_CTREE_NODE(clist->selection->data);
1820 prev_row = gtkut_ctree_get_nth_from_node
1821 (GTK_CTREE(ctree), node);
1824 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1827 if (prev_row != row) {
1828 gtk_clist_unselect_all(clist);
1829 if (event->button == 2)
1830 folderview_select_node
1832 gtk_ctree_node_nth(GTK_CTREE(ctree),
1835 gtk_clist_select_row(clist, row, column);
1839 if (event->button != 3) return FALSE;
1841 item = gtk_clist_get_row_data(clist, row);
1842 g_return_val_if_fail(item != NULL, FALSE);
1843 g_return_val_if_fail(item->folder != NULL, FALSE);
1844 folder = item->folder;
1846 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1848 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1850 fpopup = g_hash_table_lookup(folderview_popups, "common");
1851 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1854 if (fpopup->set_sensitivity != NULL)
1855 fpopup->set_sensitivity(fpopup_factory, item);
1857 if (NULL != (ac = account_find_from_item(item))) {
1858 special_trash = account_get_special_folder(ac, F_TRASH);
1859 special_queue = account_get_special_folder(ac, F_QUEUE);
1862 if ((item == folder->trash || item == special_trash
1863 || folder_has_parent_of_type(item, F_TRASH)) &&
1864 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1865 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1866 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1867 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1868 && !folder_has_parent_of_type(item, F_TRASH)) {
1869 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1870 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1873 if ((item == folder->queue || item == special_queue
1874 || folder_has_parent_of_type(item, F_QUEUE)) &&
1875 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1876 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1877 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1878 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1879 && !folder_has_parent_of_type(item, F_QUEUE)) {
1880 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1881 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1884 #define SET_SENS(name, sens) \
1885 menu_set_sensitive(fpopup_factory, name, sens)
1887 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1888 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1889 folderview->selected == folderview->opened);
1890 SET_SENS("/Properties...", TRUE);
1891 SET_SENS("/Processing...", item->node->parent != NULL);
1892 if (item == folder->trash || item == special_trash
1893 || folder_has_parent_of_type(item, F_TRASH)) {
1894 GSList *msglist = folder_item_get_msg_list(item);
1895 SET_SENS("/Empty trash...", msglist != NULL);
1896 procmsg_msg_list_free(msglist);
1898 if (item == folder->queue || item == special_queue
1899 || folder_has_parent_of_type(item, F_QUEUE)) {
1900 GSList *msglist = folder_item_get_msg_list(item);
1901 SET_SENS("/Send queue...", msglist != NULL);
1902 procmsg_msg_list_free(msglist);
1906 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1907 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1908 event->button, event->time);
1913 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1914 FolderView *folderview)
1916 if (!event) return FALSE;
1918 if (event->button == 1 && folderview->open_folder == FALSE &&
1919 folderview->opened != NULL) {
1920 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1921 folderview->opened);
1922 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1928 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1929 FolderView *folderview)
1931 if (!event) return FALSE;
1933 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1936 switch (event->keyval) {
1938 if (folderview->selected) {
1939 folderview_select_node(folderview,
1940 folderview->selected);
1944 if (folderview->selected) {
1945 if (folderview->opened == folderview->selected &&
1946 (!folderview->summaryview->folder_item ||
1947 folderview->summaryview->folder_item->total_msgs == 0))
1948 folderview_select_next_unread(folderview);
1950 folderview_select_node(folderview,
1951 folderview->selected);
1961 typedef struct _PostponedSelectData
1966 FolderView *folderview;
1967 } PostponedSelectData;
1969 static gboolean postpone_select(void *data)
1971 PostponedSelectData *psdata = (PostponedSelectData *)data;
1972 debug_print("trying again\n");
1973 psdata->folderview->open_folder = TRUE;
1974 main_window_cursor_normal(psdata->folderview->mainwin);
1975 STATUSBAR_POP(psdata->folderview->mainwin);
1976 folderview_selected(psdata->ctree, psdata->row,
1977 psdata->column, psdata->folderview);
1982 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1983 gint column, FolderView *folderview)
1985 static gboolean can_select = TRUE; /* exclusive lock */
1991 folderview->selected = row;
1993 if (folderview->opened == row) {
1994 folderview->open_folder = FALSE;
1998 if (!can_select || summary_is_locked(folderview->summaryview)) {
1999 if (folderview->opened) {
2000 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2001 gtk_ctree_select(ctree, folderview->opened);
2006 if (!folderview->open_folder) return;
2008 item = gtk_ctree_node_get_row_data(ctree, row);
2009 if (!item || item->no_select) return;
2013 /* Save cache for old folder */
2014 /* We don't want to lose all caches if sylpheed crashed */
2015 if (folderview->opened) {
2016 FolderItem *olditem;
2018 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2020 /* will be null if we just moved the previously opened folder */
2021 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2022 summary_show(folderview->summaryview, NULL);
2023 folder_item_close(olditem);
2027 /* CLAWS: set compose button type: news folder items
2028 * always have a news folder as parent */
2030 toolbar_set_compose_button
2031 (folderview->mainwin->toolbar,
2032 FOLDER_TYPE(item->folder) == F_NEWS ?
2033 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2036 debug_print("Folder %s is selected\n", item->path);
2038 if (!GTK_CTREE_ROW(row)->children)
2039 gtk_ctree_expand(ctree, row);
2040 if (folderview->opened &&
2041 !GTK_CTREE_ROW(folderview->opened)->children)
2042 gtk_ctree_collapse(ctree, folderview->opened);
2044 /* ungrab the mouse event */
2045 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2046 gtk_grab_remove(GTK_WIDGET(ctree));
2047 if (gdk_pointer_is_grabbed())
2048 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2052 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2053 item->path : "(null)");
2054 debug_print("%s\n", buf);
2055 STATUSBAR_PUSH(folderview->mainwin, buf);
2058 main_window_cursor_wait(folderview->mainwin);
2060 res = folder_item_open(item);
2062 main_window_cursor_normal(folderview->mainwin);
2063 STATUSBAR_POP(folderview->mainwin);
2065 alertpanel_error(_("Folder could not be opened."));
2067 folderview->open_folder = FALSE;
2071 } else if (res == -2) {
2072 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2073 data->ctree = ctree;
2075 data->column = column;
2076 data->folderview = folderview;
2077 debug_print("postponing open of %s till end of scan\n",
2078 item->path ? item->path:item->name);
2079 folderview->open_folder = FALSE;
2081 g_timeout_add(500, postpone_select, data);
2085 main_window_cursor_normal(folderview->mainwin);
2088 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2089 opened = summary_show(folderview->summaryview, item);
2091 folder_clean_cache_memory(item);
2094 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2095 gtk_ctree_select(ctree, folderview->opened);
2097 folderview->opened = row;
2098 if (gtk_ctree_node_is_visible(ctree, row)
2099 != GTK_VISIBILITY_FULL)
2100 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2103 STATUSBAR_POP(folderview->mainwin);
2105 folderview->open_folder = FALSE;
2109 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2110 FolderView *folderview)
2114 item = gtk_ctree_node_get_row_data(ctree, node);
2115 g_return_if_fail(item != NULL);
2116 item->collapsed = FALSE;
2117 folderview_update_node(folderview, node);
2120 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2121 FolderView *folderview)
2125 item = gtk_ctree_node_get_row_data(ctree, node);
2126 g_return_if_fail(item != NULL);
2127 item->collapsed = TRUE;
2128 folderview_update_node(folderview, node);
2131 static void folderview_popup_close(GtkMenuShell *menu_shell,
2132 FolderView *folderview)
2134 if (!folderview->opened) return;
2136 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2139 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2140 FolderView *folderview)
2142 FolderColumnType type = folderview->col_state[column].type;
2144 prefs_common.folder_col_size[type] = width;
2147 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2151 folderview_create_folder_node(folderview, item);
2153 if (!item || !item->folder || !item->folder->node)
2156 srcnode = item->folder->node;
2157 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2158 srcnode = srcnode->children;
2159 while (srcnode != NULL) {
2160 if (srcnode && srcnode->data) {
2161 FolderItem *next_item = (FolderItem*) srcnode->data;
2162 folderview_create_folder_node_recursive(folderview, next_item);
2164 srcnode = srcnode->next;
2168 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2170 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2171 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2172 GtkCTreeNode *node, *parent_node;
2173 gint *col_pos = folderview->col_pos;
2174 FolderItemUpdateData hookdata;
2176 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2177 if (parent_node == NULL)
2180 gtk_clist_freeze(GTK_CLIST(ctree));
2182 text[col_pos[F_COL_FOLDER]] = item->name;
2183 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2185 folderxpm, folderxpmmask,
2186 folderopenxpm, folderopenxpmmask,
2188 gtk_ctree_expand(ctree, parent_node);
2189 gtk_ctree_node_set_row_data(ctree, node, item);
2191 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2192 folderview_sort_folders(folderview, parent_node, item->folder);
2194 hookdata.item = item;
2195 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2196 hookdata.msg = NULL;
2197 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2199 gtk_clist_thaw(GTK_CLIST(ctree));
2202 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2205 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2207 GSList *mlist = NULL;
2209 FolderItem *special_trash = NULL;
2212 if (!folderview->selected) return;
2213 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2214 g_return_if_fail(item != NULL);
2215 g_return_if_fail(item->folder != NULL);
2217 if (NULL != (ac = account_find_from_item(item)))
2218 special_trash = account_get_special_folder(ac, F_TRASH);
2220 if (item != item->folder->trash && item != special_trash
2221 && !folder_has_parent_of_type(item, F_TRASH)) return;
2223 if (prefs_common.ask_on_clean) {
2224 if (alertpanel(_("Empty trash"),
2225 _("Delete all messages in trash?"),
2226 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2230 mlist = folder_item_get_msg_list(item);
2232 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2233 MsgInfo * msginfo = (MsgInfo *) cur->data;
2234 if (MSG_IS_LOCKED(msginfo->flags))
2236 /* is it partially received? (partial_recv isn't cached) */
2237 if (msginfo->total_size != 0 &&
2238 msginfo->size != (off_t)msginfo->total_size)
2239 partial_mark_for_delete(msginfo);
2241 procmsg_msg_list_free(mlist);
2243 folder_item_remove_all_msg(item);
2246 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2249 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2251 FolderItem *special_queue = NULL;
2253 gchar *errstr = NULL;
2255 if (!folderview->selected) return;
2256 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2257 g_return_if_fail(item != NULL);
2258 g_return_if_fail(item->folder != NULL);
2260 if (NULL != (ac = account_find_from_item(item)))
2261 special_queue = account_get_special_folder(ac, F_QUEUE);
2263 if (item != item->folder->queue && item != special_queue
2264 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2266 if (procmsg_queue_is_empty(item))
2269 if (prefs_common.work_offline)
2270 if (alertpanel(_("Offline warning"),
2271 _("You're working offline. Override?"),
2272 GTK_STOCK_NO, GTK_STOCK_YES,
2273 NULL) != G_ALERTALTERNATE)
2276 /* ask for confirmation before sending queued messages only
2277 in online mode and if there is at least one message queued
2278 in any of the folder queue
2280 if (prefs_common.confirm_send_queued_messages) {
2281 if (!prefs_common.work_offline) {
2282 if (alertpanel(_("Send queued messages"),
2283 _("Send all queued messages?"),
2284 GTK_STOCK_CANCEL, _("_Send"),
2285 NULL) != G_ALERTALTERNATE)
2290 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2292 alertpanel_error_log(_("Some errors occurred while "
2293 "sending queued messages."));
2295 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2296 "while sending queued messages:\n%s"), errstr);
2298 alertpanel_error_log(tmp);
2304 static void folderview_search_cb(FolderView *folderview, guint action,
2307 summary_search(folderview->summaryview);
2310 static void folderview_property_cb(FolderView *folderview, guint action,
2313 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2316 if (!folderview->selected) return;
2318 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2319 g_return_if_fail(item != NULL);
2320 g_return_if_fail(item->folder != NULL);
2322 prefs_folder_item_open(item);
2325 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2327 GSList *list = NULL;
2328 GSList *done = NULL;
2329 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2331 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2332 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2333 && list->data != node) {
2334 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2335 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2338 for (list = done; list != NULL; list = g_slist_next(list)) {
2339 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2345 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2346 FolderItem *to_folder)
2348 FolderItem *from_parent = NULL;
2349 FolderItem *new_folder = NULL;
2350 GtkCTreeNode *src_node = NULL;
2354 g_return_if_fail(folderview != NULL);
2355 g_return_if_fail(from_folder != NULL);
2356 g_return_if_fail(to_folder != NULL);
2358 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2359 from_parent = folder_item_parent(from_folder);
2361 if (prefs_common.warn_dnd) {
2362 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2363 "sub-folder of '%s' ?"), from_folder->name,
2365 status = alertpanel_full(_("Move folder"), buf,
2366 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2367 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2370 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2372 else if (status & G_ALERTDISABLE)
2373 prefs_common.warn_dnd = FALSE;
2376 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2377 STATUSBAR_PUSH(folderview->mainwin, buf);
2379 summary_clear_all(folderview->summaryview);
2380 folderview->opened = NULL;
2381 folderview->selected = NULL;
2382 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2384 main_window_cursor_wait(folderview->mainwin);
2385 statusbar_verbosity_set(TRUE);
2386 folder_item_update_freeze();
2387 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2388 statusbar_verbosity_set(FALSE);
2389 main_window_cursor_normal(folderview->mainwin);
2390 STATUSBAR_POP(folderview->mainwin);
2391 folder_item_update_thaw();
2392 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2394 folderview_sort_folders(folderview,
2395 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2396 NULL, to_folder), new_folder->folder);
2397 folderview_select(folderview, new_folder);
2399 statusbar_verbosity_set(FALSE);
2400 main_window_cursor_normal(folderview->mainwin);
2401 STATUSBAR_POP(folderview->mainwin);
2402 folder_item_update_thaw();
2404 case F_MOVE_FAILED_DEST_IS_PARENT:
2405 alertpanel_error(_("Source and destination are the same."));
2407 case F_MOVE_FAILED_DEST_IS_CHILD:
2408 alertpanel_error(_("Can't move a folder to one of its children."));
2410 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2411 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2414 alertpanel_error(_("Move failed!"));
2419 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2422 static gint folderview_clist_compare(GtkCList *clist,
2423 gconstpointer ptr1, gconstpointer ptr2)
2425 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2426 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2429 return (item2->name != NULL);
2433 return g_utf8_collate(item1->name, item2->name);
2436 static void folderview_processing_cb(FolderView *folderview, guint action,
2439 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2443 if (!folderview->selected) return;
2445 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2446 g_return_if_fail(item != NULL);
2447 g_return_if_fail(item->folder != NULL);
2449 id = folder_item_get_identifier(item);
2450 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2453 prefs_filtering_open(&item->prefs->processing, title, NULL, NULL);
2457 void folderview_set_target_folder_color(gint color_op)
2461 FolderView *folderview;
2463 for (list = folderview_list; list != NULL; list = list->next) {
2464 folderview = (FolderView *)list->data;
2465 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2467 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2468 folderview->color_op;
2474 static gchar *last_font = NULL;
2475 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2483 void folderview_reflect_prefs(void)
2485 gboolean update_font = TRUE;
2486 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2487 FolderItem *item = folderview_get_selected_item(folderview);
2488 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2489 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2490 gint height = pos->value;
2492 if (last_font && !strcmp(last_font, NORMAL_FONT))
2493 update_font = FALSE;
2496 last_font = g_strdup(NORMAL_FONT);
2499 normal_style = normal_color_style = bold_style =
2500 bold_color_style = bold_tgtfold_style = NULL;
2502 folderview_init(folderview);
2504 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2505 folderview_column_set_titles(folderview);
2506 folderview_set_all();
2508 g_signal_handlers_block_by_func
2509 (G_OBJECT(folderview->ctree),
2510 G_CALLBACK(folderview_selected), folderview);
2513 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2514 GTK_CTREE(folderview->ctree), NULL, item);
2516 folderview_select(folderview, item);
2517 folderview->selected = node;
2520 g_signal_handlers_unblock_by_func
2521 (G_OBJECT(folderview->ctree),
2522 G_CALLBACK(folderview_selected), folderview);
2524 pos = gtk_scrolled_window_get_vadjustment(
2525 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2526 gtk_adjustment_set_value(pos, height);
2527 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2530 static void drag_state_stop(FolderView *folderview)
2532 if (folderview->drag_timer)
2533 gtk_timeout_remove(folderview->drag_timer);
2534 folderview->drag_timer = 0;
2535 folderview->drag_node = NULL;
2538 static gint folderview_defer_expand(FolderView *folderview)
2540 if (folderview->drag_node) {
2541 folderview_recollapse_nodes(folderview, folderview->drag_node);
2542 if (folderview->drag_item->collapsed) {
2543 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2544 folderview->nodes_to_recollapse = g_slist_append
2545 (folderview->nodes_to_recollapse, folderview->drag_node);
2548 folderview->drag_item = NULL;
2549 folderview->drag_timer = 0;
2553 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2555 /* the idea is that we call drag_state_start() whenever we want expansion to
2556 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2557 * we need to call drag_state_stop() */
2558 drag_state_stop(folderview);
2559 /* request expansion */
2560 if (0 != (folderview->drag_timer = gtk_timeout_add
2561 (prefs_common.hover_timeout,
2562 (GtkFunction)folderview_defer_expand,
2564 folderview->drag_node = node;
2565 folderview->drag_item = item;
2569 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2570 FolderView *folderview)
2572 GdkDragContext *context;
2574 g_return_if_fail(folderview != NULL);
2575 if (folderview->selected == NULL) return;
2576 if (folderview->nodes_to_recollapse)
2577 g_slist_free(folderview->nodes_to_recollapse);
2578 folderview->nodes_to_recollapse = NULL;
2579 context = gtk_drag_begin(widget, folderview->target_list,
2580 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2581 gtk_drag_set_icon_default(context);
2584 static void folderview_drag_data_get(GtkWidget *widget,
2585 GdkDragContext *drag_context,
2586 GtkSelectionData *selection_data,
2589 FolderView *folderview)
2593 gchar *source = NULL;
2594 if (info == TARGET_DUMMY) {
2595 for (cur = GTK_CLIST(folderview->ctree)->selection;
2596 cur != NULL; cur = cur->next) {
2597 item = gtk_ctree_node_get_row_data
2598 (GTK_CTREE(folderview->ctree),
2599 GTK_CTREE_NODE(cur->data));
2601 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2602 gtk_selection_data_set(selection_data,
2603 selection_data->target, 8,
2604 source, strlen(source));
2610 g_warning("unknown info %d\n", info);
2614 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2616 FolderUpdateData *hookdata;
2617 FolderView *folderview;
2621 folderview = (FolderView *) userdata;
2622 g_return_val_if_fail(hookdata != NULL, FALSE);
2623 g_return_val_if_fail(folderview != NULL, FALSE);
2625 ctree = folderview->ctree;
2626 g_return_val_if_fail(ctree != NULL, FALSE);
2628 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2629 folderview_create_folder_node(folderview, hookdata->item);
2630 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2631 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2632 NULL, folder_item_parent(hookdata->item));
2633 folderview_sort_folders(folderview, node, hookdata->folder);
2634 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2637 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2639 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2640 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2641 folderview_set(folderview);
2646 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2647 GdkDragContext *context,
2651 FolderView *folderview)
2654 FolderItem *item = NULL, *src_item = NULL;
2655 GtkCTreeNode *node = NULL;
2656 gboolean acceptable = FALSE;
2657 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2658 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2659 int height = (int)pos->page_size;
2660 int total_height = (int)pos->upper;
2661 int vpos = (int) pos->value;
2663 if (gtk_clist_get_selection_info
2664 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2665 GtkWidget *srcwidget;
2667 if (y > height - 24 && height + vpos < total_height)
2668 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2670 if (y < 48 && y > 0)
2671 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2673 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2674 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2675 src_item = folderview->summaryview->folder_item;
2677 srcwidget = gtk_drag_get_source_widget(context);
2678 if (srcwidget == folderview->summaryview->ctree) {
2679 /* comes from summaryview */
2680 /* we are copying messages, so only accept folder items that are not
2681 the source item, are no root items and can copy messages */
2682 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2683 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2685 } else if (srcwidget == folderview->ctree) {
2686 /* comes from folderview */
2687 /* we are moving folder items, only accept folders that are not
2688 the source items and can copy messages and create folder items */
2689 if (item && item->folder && src_item && src_item != item &&
2690 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2691 FOLDER_CLASS(item->folder)->create_folder != NULL)
2694 /* comes from another app */
2695 /* we are adding messages, so only accept folder items that are
2696 no root items and can copy messages */
2697 if (item && item->folder && folder_item_parent(item) != NULL
2698 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2703 if (acceptable || (src_item && src_item == item))
2704 drag_state_start(folderview, node, item);
2707 g_signal_handlers_block_by_func
2709 G_CALLBACK(folderview_selected), folderview);
2710 gtk_ctree_select(GTK_CTREE(widget), node);
2711 g_signal_handlers_unblock_by_func
2713 G_CALLBACK(folderview_selected), folderview);
2714 gdk_drag_status(context,
2715 (context->actions == GDK_ACTION_COPY ?
2716 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2718 if (folderview->opened)
2719 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2720 gdk_drag_status(context, 0, time);
2726 static void folderview_drag_leave_cb(GtkWidget *widget,
2727 GdkDragContext *context,
2729 FolderView *folderview)
2731 drag_state_stop(folderview);
2732 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2735 static void free_info (gpointer stuff, gpointer data)
2740 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2741 guint time, FolderItem *item)
2744 GSList *msglist = NULL;
2745 list = uri_list_extract_filenames(data);
2746 if (!(item && item->folder && folder_item_parent(item) != NULL
2747 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2749 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2753 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2756 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2757 MsgFileInfo *info = NULL;
2759 if (file_is_email((gchar *)tmp->data)) {
2760 info = g_new0(MsgFileInfo, 1);
2761 info->msginfo = NULL;
2762 info->file = (gchar *)tmp->data;
2763 msglist = g_slist_prepend(msglist, info);
2767 msglist = g_slist_reverse(msglist);
2768 folder_item_add_msgs(item, msglist, FALSE);
2769 g_slist_foreach(msglist, free_info, NULL);
2770 g_slist_free(msglist);
2771 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2773 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2775 list_free_strings(list);
2779 static void folderview_drag_received_cb(GtkWidget *widget,
2780 GdkDragContext *drag_context,
2783 GtkSelectionData *data,
2786 FolderView *folderview)
2789 FolderItem *item = NULL, *src_item;
2792 if (info == TARGET_DUMMY) {
2793 drag_state_stop(folderview);
2794 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2795 /* comes from summaryview */
2796 if (gtk_clist_get_selection_info
2797 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2800 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2801 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2802 src_item = folderview->summaryview->folder_item;
2804 /* re-check (due to acceptable possibly set for folder moves */
2805 if (!(item && item->folder && item->path && !item->no_select &&
2806 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2809 if (item && src_item) {
2810 switch (drag_context->action) {
2811 case GDK_ACTION_COPY:
2812 summary_copy_selected_to(folderview->summaryview, item);
2813 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2815 case GDK_ACTION_MOVE:
2816 case GDK_ACTION_DEFAULT:
2818 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2819 summary_copy_selected_to(folderview->summaryview, item);
2821 summary_move_selected_to(folderview->summaryview, item);
2822 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2825 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2827 /* comes from folderview */
2829 gboolean folder_is_normal = TRUE;
2831 source = data->data + 17;
2832 if (gtk_clist_get_selection_info
2833 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2835 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2838 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2839 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2840 src_item = folder_find_item_from_identifier(source);
2844 src_item->stype == F_NORMAL &&
2845 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2846 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2847 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2848 !folder_has_parent_of_type(src_item, F_TRASH);
2849 if (!item || item->no_select || !src_item
2850 || !folder_is_normal) {
2851 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2855 folderview_move_folder(folderview, src_item, item);
2856 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2858 folderview->nodes_to_recollapse = NULL;
2859 } else if (info == TARGET_MAIL_URI_LIST) {
2860 if (gtk_clist_get_selection_info
2861 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2864 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2866 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2869 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2871 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2874 folderview_finish_dnd(data->data, drag_context, time, item);
2878 static void folderview_drag_end_cb(GtkWidget *widget,
2879 GdkDragContext *drag_context,
2880 FolderView *folderview)
2882 drag_state_stop(folderview);
2883 g_slist_free(folderview->nodes_to_recollapse);
2884 folderview->nodes_to_recollapse = NULL;
2887 void folderview_register_popup(FolderViewPopup *fpopup)
2891 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2892 FolderView *folderview = folderviews->data;
2893 GtkItemFactory *factory;
2895 factory = create_ifactory(folderview, fpopup);
2896 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2898 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2901 void folderview_unregister_popup(FolderViewPopup *fpopup)
2905 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2906 FolderView *folderview = folderviews->data;
2908 g_hash_table_remove(folderview->popups, fpopup->klass);
2910 g_hash_table_remove(folderview_popups, fpopup->klass);