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"
70 #define COL_FOLDER_WIDTH 150
71 #define COL_NUM_WIDTH 32
73 static GList *folderview_list = NULL;
75 static GtkStyle *normal_style;
76 static GtkStyle *normal_color_style;
77 static GtkStyle *bold_style;
78 static GtkStyle *bold_color_style;
79 static GtkStyle *bold_tgtfold_style;
81 static GdkPixmap *inboxxpm;
82 static GdkBitmap *inboxxpmmask;
83 static GdkPixmap *inboxhrmxpm;
84 static GdkBitmap *inboxhrmxpmmask;
85 static GdkPixmap *inboxopenxpm;
86 static GdkBitmap *inboxopenxpmmask;
87 static GdkPixmap *inboxopenhrmxpm;
88 static GdkBitmap *inboxopenhrmxpmmask;
89 static GdkPixmap *outboxxpm;
90 static GdkBitmap *outboxxpmmask;
91 static GdkPixmap *outboxhrmxpm;
92 static GdkBitmap *outboxhrmxpmmask;
93 static GdkPixmap *outboxopenxpm;
94 static GdkBitmap *outboxopenxpmmask;
95 static GdkPixmap *outboxopenhrmxpm;
96 static GdkBitmap *outboxopenhrmxpmmask;
97 static GdkPixmap *folderxpm;
98 static GdkBitmap *folderxpmmask;
99 static GdkPixmap *folderhrmxpm;
100 static GdkBitmap *folderhrmxpmmask;
101 static GdkPixmap *folderopenxpm;
102 static GdkBitmap *folderopenxpmmask;
103 static GdkPixmap *folderopenhrmxpm;
104 static GdkBitmap *folderopenhrmxpmmask;
105 static GdkPixmap *trashopenxpm;
106 static GdkBitmap *trashopenxpmmask;
107 static GdkPixmap *trashopenhrmxpm;
108 static GdkBitmap *trashopenhrmxpmmask;
109 static GdkPixmap *trashxpm;
110 static GdkBitmap *trashxpmmask;
111 static GdkPixmap *trashhrmxpm;
112 static GdkBitmap *trashhrmxpmmask;
113 static GdkPixmap *queuexpm;
114 static GdkBitmap *queuexpmmask;
115 static GdkPixmap *queuehrmxpm;
116 static GdkBitmap *queuehrmxpmmask;
117 static GdkPixmap *queueopenxpm;
118 static GdkBitmap *queueopenxpmmask;
119 static GdkPixmap *queueopenhrmxpm;
120 static GdkBitmap *queueopenhrmxpmmask;
121 static GdkPixmap *draftsxpm;
122 static GdkBitmap *draftsxpmmask;
123 static GdkPixmap *draftsopenxpm;
124 static GdkBitmap *draftsopenxpmmask;
125 static GdkPixmap *noselectxpm;
126 static GdkBitmap *noselectxpmmask;
128 static GdkPixmap *m_inboxxpm;
129 static GdkBitmap *m_inboxxpmmask;
130 static GdkPixmap *m_inboxhrmxpm;
131 static GdkBitmap *m_inboxhrmxpmmask;
132 static GdkPixmap *m_inboxopenxpm;
133 static GdkBitmap *m_inboxopenxpmmask;
134 static GdkPixmap *m_inboxopenhrmxpm;
135 static GdkBitmap *m_inboxopenhrmxpmmask;
136 static GdkPixmap *m_outboxxpm;
137 static GdkBitmap *m_outboxxpmmask;
138 static GdkPixmap *m_outboxhrmxpm;
139 static GdkBitmap *m_outboxhrmxpmmask;
140 static GdkPixmap *m_outboxopenxpm;
141 static GdkBitmap *m_outboxopenxpmmask;
142 static GdkPixmap *m_outboxopenhrmxpm;
143 static GdkBitmap *m_outboxopenhrmxpmmask;
144 static GdkPixmap *m_folderxpm;
145 static GdkBitmap *m_folderxpmmask;
146 static GdkPixmap *m_folderhrmxpm;
147 static GdkBitmap *m_folderhrmxpmmask;
148 static GdkPixmap *m_folderopenxpm;
149 static GdkBitmap *m_folderopenxpmmask;
150 static GdkPixmap *m_folderopenhrmxpm;
151 static GdkBitmap *m_folderopenhrmxpmmask;
152 static GdkPixmap *m_trashopenxpm;
153 static GdkBitmap *m_trashopenxpmmask;
154 static GdkPixmap *m_trashopenhrmxpm;
155 static GdkBitmap *m_trashopenhrmxpmmask;
156 static GdkPixmap *m_trashxpm;
157 static GdkBitmap *m_trashxpmmask;
158 static GdkPixmap *m_trashhrmxpm;
159 static GdkBitmap *m_trashhrmxpmmask;
160 static GdkPixmap *m_queuexpm;
161 static GdkBitmap *m_queuexpmmask;
162 static GdkPixmap *m_queuehrmxpm;
163 static GdkBitmap *m_queuehrmxpmmask;
164 static GdkPixmap *m_queueopenxpm;
165 static GdkBitmap *m_queueopenxpmmask;
166 static GdkPixmap *m_queueopenhrmxpm;
167 static GdkBitmap *m_queueopenhrmxpmmask;
168 static GdkPixmap *m_draftsxpm;
169 static GdkBitmap *m_draftsxpmmask;
170 static GdkPixmap *m_draftsopenxpm;
171 static GdkBitmap *m_draftsopenxpmmask;
173 static GdkPixmap *newxpm;
174 static GdkBitmap *newxpmmask;
175 static GdkPixmap *unreadxpm;
176 static GdkBitmap *unreadxpmmask;
177 static GdkPixmap *readxpm;
178 static GdkBitmap *readxpmmask;
181 static void folderview_select_node (FolderView *folderview,
183 static void folderview_set_folders (FolderView *folderview);
184 static void folderview_sort_folders (FolderView *folderview,
187 static void folderview_append_folder (FolderView *folderview,
189 static void folderview_update_node (FolderView *folderview,
192 static gint folderview_clist_compare (GtkCList *clist,
196 /* callback functions */
197 static gboolean folderview_button_pressed (GtkWidget *ctree,
198 GdkEventButton *event,
199 FolderView *folderview);
200 static gboolean folderview_button_released (GtkWidget *ctree,
201 GdkEventButton *event,
202 FolderView *folderview);
203 static gboolean folderview_key_pressed (GtkWidget *widget,
205 FolderView *folderview);
206 static void folderview_selected (GtkCTree *ctree,
209 FolderView *folderview);
210 static void folderview_tree_expanded (GtkCTree *ctree,
212 FolderView *folderview);
213 static void folderview_tree_collapsed (GtkCTree *ctree,
215 FolderView *folderview);
216 static void folderview_popup_close (GtkMenuShell *menu_shell,
217 FolderView *folderview);
218 static void folderview_col_resized (GtkCList *clist,
221 FolderView *folderview);
223 static void mark_all_read_cb (FolderView *folderview,
227 static void folderview_empty_trash_cb (FolderView *folderview,
231 static void folderview_send_queue_cb (FolderView *folderview,
235 static void folderview_search_cb (FolderView *folderview,
239 static void folderview_property_cb (FolderView *folderview,
243 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
244 GdkDragContext *context,
248 FolderView *folderview);
249 static void folderview_drag_leave_cb (GtkWidget *widget,
250 GdkDragContext *context,
252 FolderView *folderview);
253 static void folderview_drag_received_cb (GtkWidget *widget,
254 GdkDragContext *drag_context,
257 GtkSelectionData *data,
260 FolderView *folderview);
261 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
262 FolderView *folderview);
263 static void folderview_drag_data_get (GtkWidget *widget,
264 GdkDragContext *drag_context,
265 GtkSelectionData *selection_data,
268 FolderView *folderview);
269 static void folderview_drag_end_cb (GtkWidget *widget,
270 GdkDragContext *drag_context,
271 FolderView *folderview);
273 void folderview_create_folder_node (FolderView *folderview,
275 gboolean folderview_update_folder (gpointer source,
277 gboolean folderview_update_item_claws (gpointer source,
279 static void folderview_processing_cb(FolderView *folderview, guint action,
282 GHashTable *folderview_popups;
284 static GtkItemFactoryEntry folderview_common_popup_entries[] =
286 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
287 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
288 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
289 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
292 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
293 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
294 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
297 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
298 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
299 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
303 GtkTargetEntry folderview_drag_types[] =
305 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
306 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
309 void folderview_initialize(void)
311 FolderViewPopup *fpopup;
313 GSList *entries = NULL;
315 fpopup = g_new0(FolderViewPopup, 1);
317 n_entries = sizeof(folderview_common_popup_entries) /
318 sizeof(folderview_common_popup_entries[0]);
319 for (i = 0; i < n_entries; i++)
320 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
322 fpopup->klass = "common";
323 fpopup->path = "<CommonFolder>";
324 fpopup->entries = entries;
325 fpopup->set_sensitivity = NULL;
327 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
328 g_hash_table_insert(folderview_popups, "common", fpopup);
331 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
334 GtkItemFactory *factory;
335 FolderViewPopup *fpopup_common;
338 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
339 gtk_item_factory_set_translate_func(factory, menu_translate,
342 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
343 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
345 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
346 if (fpopup_common != fpopup)
347 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
348 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
350 popup = gtk_item_factory_get_widget(factory, fpopup->path);
351 g_signal_connect(G_OBJECT(popup), "selection_done",
352 G_CALLBACK(folderview_popup_close),
358 static void create_ifactories(gpointer key, gpointer value, gpointer data)
360 FolderView *folderview = data;
361 FolderViewPopup *fpopup = value;
362 GtkItemFactory *factory;
364 factory = create_ifactory(folderview, fpopup);
365 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
368 static void folderview_column_set_titles(FolderView *folderview)
370 GtkWidget *ctree = folderview->ctree;
371 GtkWidget *label_new;
372 GtkWidget *label_unread;
373 GtkWidget *label_total;
375 GtkWidget *hbox_unread;
376 GtkWidget *hbox_total;
377 gint *col_pos = folderview->col_pos;
379 debug_print("setting titles...\n");
380 gtk_widget_realize(folderview->ctree);
381 gtk_widget_show_all(folderview->scrolledwin);
383 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
384 * instead text (text overflows making them unreadable and ugly) */
385 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
386 &newxpm, &newxpmmask);
387 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
388 &unreadxpm, &unreadxpmmask);
389 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
390 &readxpm, &readxpmmask);
392 label_new = gtk_pixmap_new(newxpm, newxpmmask);
393 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
394 label_total = gtk_pixmap_new(readxpm, readxpmmask);
396 hbox_new = gtk_hbox_new(FALSE, 4);
397 hbox_unread = gtk_hbox_new(FALSE, 4);
398 hbox_total = gtk_hbox_new(FALSE, 4);
401 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
402 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
403 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
404 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
405 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
406 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
408 gtk_widget_show_all(hbox_new);
409 gtk_widget_show_all(hbox_unread);
410 gtk_widget_show_all(hbox_total);
412 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
413 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
414 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
417 GtkWidget *folderview_ctree_create(FolderView *folderview)
421 FolderColumnState *col_state;
422 FolderColumnType type;
423 gchar *titles[N_FOLDER_COLS];
425 GtkWidget *scrolledwin = folderview->scrolledwin;
427 debug_print("creating tree...\n");
428 memset(titles, 0, sizeof(titles));
430 col_state = prefs_folder_column_get_config();
431 memset(titles, 0, sizeof(titles));
433 col_pos = folderview->col_pos;
435 for (i = 0; i < N_FOLDER_COLS; i++) {
436 folderview->col_state[i] = col_state[i];
437 type = col_state[i].type;
441 titles[col_pos[F_COL_FOLDER]] = _("Folder");
442 titles[col_pos[F_COL_NEW]] = _("New");
443 titles[col_pos[F_COL_UNREAD]] = _("Unread");
444 /* TRANSLATORS: This in Number sign in American style */
445 titles[col_pos[F_COL_TOTAL]] = _("#");
447 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
450 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
451 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
453 gtk_clist_set_column_justification(GTK_CLIST(ctree),
454 col_pos[F_COL_UNREAD],
456 gtk_clist_set_column_justification(GTK_CLIST(ctree),
457 col_pos[F_COL_TOTAL],
459 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
460 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
461 GTK_CTREE_EXPANDER_SQUARE);
462 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
463 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
465 /* don't let title buttons take key focus */
466 for (i = 0; i < N_FOLDER_COLS; i++) {
467 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
469 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
470 prefs_common.folder_col_size[i]);
471 gtk_clist_set_column_visibility
472 (GTK_CLIST(ctree), i, col_state[i].visible);
475 g_signal_connect(G_OBJECT(ctree), "key_press_event",
476 G_CALLBACK(folderview_key_pressed),
478 g_signal_connect(G_OBJECT(ctree), "button_press_event",
479 G_CALLBACK(folderview_button_pressed),
481 g_signal_connect(G_OBJECT(ctree), "button_release_event",
482 G_CALLBACK(folderview_button_released),
484 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
485 G_CALLBACK(folderview_selected), folderview);
486 g_signal_connect(G_OBJECT(ctree), "start_drag",
487 G_CALLBACK(folderview_start_drag), folderview);
488 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
489 G_CALLBACK(folderview_drag_data_get),
492 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
493 G_CALLBACK(folderview_tree_expanded),
495 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
496 G_CALLBACK(folderview_tree_collapsed),
499 g_signal_connect(G_OBJECT(ctree), "resize_column",
500 G_CALLBACK(folderview_col_resized),
504 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
505 folderview_drag_types, 2,
506 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
507 g_signal_connect(G_OBJECT(ctree), "drag_motion",
508 G_CALLBACK(folderview_drag_motion_cb),
510 g_signal_connect(G_OBJECT(ctree), "drag_leave",
511 G_CALLBACK(folderview_drag_leave_cb),
513 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
514 G_CALLBACK(folderview_drag_received_cb),
516 g_signal_connect(G_OBJECT(ctree), "drag_end",
517 G_CALLBACK(folderview_drag_end_cb),
520 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
525 void folderview_set_column_order(FolderView *folderview)
528 FolderItem *item = folderview_get_selected_item(folderview);
529 GtkWidget *scrolledwin = folderview->scrolledwin;
531 debug_print("recreating tree...\n");
532 gtk_widget_destroy(folderview->ctree);
534 folderview->ctree = ctree = folderview_ctree_create(folderview);
535 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
536 GTK_CLIST(ctree)->hadjustment);
537 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
538 GTK_CLIST(ctree)->vadjustment);
539 gtk_widget_show(ctree);
541 folderview_set(folderview);
542 folderview_column_set_titles(folderview);
544 folderview_select(folderview,item);
547 FolderView *folderview_create(void)
549 FolderView *folderview;
550 GtkWidget *scrolledwin;
553 debug_print("Creating folder view...\n");
554 folderview = g_new0(FolderView, 1);
556 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
557 gtk_scrolled_window_set_policy
558 (GTK_SCROLLED_WINDOW(scrolledwin),
559 GTK_POLICY_AUTOMATIC,
560 prefs_common.folderview_vscrollbar_policy);
561 gtk_widget_set_size_request(scrolledwin,
562 prefs_common.folderview_width,
563 prefs_common.folderview_height);
565 folderview->scrolledwin = scrolledwin;
566 ctree = folderview_ctree_create(folderview);
568 /* create popup factories */
569 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
570 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
572 folderview->ctree = ctree;
574 folderview->folder_update_callback_id =
575 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
576 folderview->folder_item_update_callback_id =
577 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
579 gtk_widget_show_all(scrolledwin);
581 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
582 folderview_list = g_list_append(folderview_list, folderview);
587 void folderview_init(FolderView *folderview)
589 GtkWidget *ctree = folderview->ctree;
592 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
593 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
594 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
595 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
596 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
597 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
598 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
599 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
600 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
601 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
602 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
603 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
604 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
605 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
606 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
607 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
608 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
609 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
610 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
611 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
612 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
613 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
614 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
616 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
617 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
618 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
619 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
620 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
621 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
622 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
623 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
640 PangoFontDescription *font_desc;
641 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
642 font_desc = pango_font_description_from_string(NORMAL_FONT);
644 if (normal_style->font_desc)
645 pango_font_description_free
646 (normal_style->font_desc);
647 normal_style->font_desc = font_desc;
649 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
650 normal_color_style = gtk_style_copy(normal_style);
651 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
653 gtk_widget_set_style(ctree, normal_style);
657 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
658 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
659 pango_font_description_set_weight
660 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
661 bold_color_style = gtk_style_copy(bold_style);
662 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
664 bold_tgtfold_style = gtk_style_copy(bold_style);
665 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
669 void folderview_set(FolderView *folderview)
671 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
672 MainWindow *mainwin = folderview->mainwin;
677 debug_print("Setting folder info...\n");
678 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
680 main_window_cursor_wait(mainwin);
682 folderview->selected = NULL;
683 folderview->opened = NULL;
685 gtk_clist_freeze(GTK_CLIST(ctree));
686 gtk_clist_clear(GTK_CLIST(ctree));
687 gtk_clist_thaw(GTK_CLIST(ctree));
688 gtk_clist_freeze(GTK_CLIST(ctree));
690 folderview_set_folders(folderview);
692 gtk_clist_thaw(GTK_CLIST(ctree));
693 main_window_cursor_normal(mainwin);
694 STATUSBAR_POP(mainwin);
697 void folderview_set_all(void)
701 for (list = folderview_list; list != NULL; list = list->next)
702 folderview_set((FolderView *)list->data);
705 void folderview_select(FolderView *folderview, FolderItem *item)
707 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
709 GtkCTreeNode *old_selected = folderview->selected;
713 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
714 if (node) folderview_select_node(folderview, node);
716 if (old_selected != node)
717 folder_update_op_count();
720 static void mark_all_read_cb(FolderView *folderview, guint action,
726 item = folderview_get_selected_item(folderview);
730 if (folderview->summaryview->folder_item != item
731 && prefs_common.ask_mark_all_read) {
732 val = alertpanel_full(_("Mark all as read"),
733 _("Do you really want to mark all mails in this "
734 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
735 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
737 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
739 else if (val & G_ALERTDISABLE)
740 prefs_common.ask_mark_all_read = FALSE;
743 summary_lock(folderview->summaryview);
744 folder_item_update_freeze();
745 if (folderview->summaryview->folder_item == item)
746 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
747 folderutils_mark_all_read(item);
748 if (folderview->summaryview->folder_item == item)
749 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
750 folder_item_update_thaw();
751 summary_unlock(folderview->summaryview);
754 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
756 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
758 g_return_if_fail(node != NULL);
760 folderview->open_folder = TRUE;
761 gtkut_ctree_set_focus_row(ctree, node);
762 gtk_ctree_select(ctree, node);
763 if (folderview->summaryview->folder_item &&
764 folderview->summaryview->folder_item->total_msgs > 0)
765 gtk_widget_grab_focus(folderview->summaryview->ctree);
767 gtk_widget_grab_focus(folderview->ctree);
769 gtkut_ctree_expand_parent_all(ctree, node);
772 void folderview_unselect(FolderView *folderview)
774 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
776 (GTK_CTREE(folderview->ctree), folderview->opened);
778 folderview->selected = folderview->opened = NULL;
781 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
787 node = gtkut_ctree_node_next(ctree, node);
789 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
791 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
792 item = gtk_ctree_node_get_row_data(ctree, node);
793 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
800 void folderview_select_next_marked(FolderView *folderview)
802 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
803 GtkCTreeNode *node = NULL;
804 SelectOnEntry last_sel = prefs_common.select_on_entry;
805 gboolean last_open = prefs_common.always_show_msg;
807 prefs_common.select_on_entry = SELECTONENTRY_MNU;
808 prefs_common.always_show_msg = TRUE;
810 if ((node = folderview_find_next_marked(ctree, folderview->opened))
812 folderview_select_node(folderview, node);
816 if (!folderview->opened ||
817 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
820 /* search again from the first node */
821 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
822 folderview_select_node(folderview, node);
825 prefs_common.select_on_entry = last_sel;
826 prefs_common.always_show_msg = last_open;
829 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
835 node = gtkut_ctree_node_next(ctree, node);
837 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
839 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
840 item = gtk_ctree_node_get_row_data(ctree, node);
841 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
848 void folderview_select_next_unread(FolderView *folderview)
850 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
851 GtkCTreeNode *node = NULL;
852 SelectOnEntry last_sel = prefs_common.select_on_entry;
853 gboolean last_open = prefs_common.always_show_msg;
855 prefs_common.select_on_entry = SELECTONENTRY_UNM;
856 prefs_common.always_show_msg = TRUE;
858 if ((node = folderview_find_next_unread(ctree, folderview->opened))
860 folderview_select_node(folderview, node);
864 if (!folderview->opened ||
865 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
868 /* search again from the first node */
869 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
870 folderview_select_node(folderview, node);
873 prefs_common.select_on_entry = last_sel;
874 prefs_common.always_show_msg = last_open;
877 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
883 node = gtkut_ctree_node_next(ctree, node);
885 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
887 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
888 item = gtk_ctree_node_get_row_data(ctree, node);
889 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
896 void folderview_select_next_new(FolderView *folderview)
898 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
899 GtkCTreeNode *node = NULL;
900 SelectOnEntry last_sel = prefs_common.select_on_entry;
901 gboolean last_open = prefs_common.always_show_msg;
903 prefs_common.select_on_entry = SELECTONENTRY_NUM;
904 prefs_common.always_show_msg = TRUE;
906 if ((node = folderview_find_next_new(ctree, folderview->opened))
908 folderview_select_node(folderview, node);
912 if (!folderview->opened ||
913 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
916 /* search again from the first node */
917 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
918 folderview_select_node(folderview, node);
921 prefs_common.select_on_entry = last_sel;
922 prefs_common.always_show_msg = last_open;
925 FolderItem *folderview_get_selected_item(FolderView *folderview)
927 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
929 if (!folderview->selected) return NULL;
930 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
933 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
935 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
936 static GtkCTreeNode *prev_row = NULL;
938 gint new, unread, total;
939 gchar *new_str, *unread_str, *total_str;
940 gint *col_pos = folderview->col_pos;
944 item = gtk_ctree_node_get_row_data(ctree, row);
947 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
948 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
949 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
951 unread = atoi(unread_str);
952 total = atoi(total_str);
956 folderview_update_node(folderview, row);
959 void folderview_append_item(FolderItem *item)
963 g_return_if_fail(item != NULL);
964 g_return_if_fail(item->folder != NULL);
965 if (folder_item_parent(item)) return;
967 for (list = folderview_list; list != NULL; list = list->next) {
968 FolderView *folderview = (FolderView *)list->data;
969 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
970 GtkCTreeNode *node, *child;
971 gint *col_pos = folderview->col_pos;
973 node = gtk_ctree_find_by_row_data(ctree, NULL,
974 folder_item_parent(item));
976 child = gtk_ctree_find_by_row_data(ctree, node, item);
978 gchar *text[N_FOLDER_COLS] =
979 {NULL, "0", "0", "0"};
981 gtk_clist_freeze(GTK_CLIST(ctree));
983 text[col_pos[F_COL_FOLDER]] = item->name;
984 child = gtk_sctree_insert_node
985 (ctree, node, NULL, text,
987 folderxpm, folderxpmmask,
988 folderopenxpm, folderopenxpmmask,
990 gtk_ctree_node_set_row_data(ctree, child, item);
991 gtk_ctree_expand(ctree, node);
992 folderview_update_node(folderview, child);
993 folderview_sort_folders(folderview, node,
996 gtk_clist_thaw(GTK_CLIST(ctree));
1002 static void folderview_set_folders(FolderView *folderview)
1005 #ifndef HAVE_LIBETPAN
1006 static gboolean missing_imap_warning = TRUE;
1008 list = folder_get_list();
1010 for (; list != NULL; list = list->next) {
1011 #ifndef HAVE_LIBETPAN
1012 if ((FOLDER(list->data))
1013 && (FOLDER(list->data))->klass
1014 && (FOLDER(list->data))->klass->type == F_IMAP
1015 && missing_imap_warning) {
1016 missing_imap_warning = FALSE;
1018 _("You have one or more IMAP accounts "
1019 "defined. However this version of "
1020 "Sylpheed-Claws has been built without "
1021 "IMAP support; your IMAP account(s) are "
1023 "You probably need to "
1024 "install libetpan and recompile "
1025 "Sylpheed-Claws."));
1028 folderview_append_folder(folderview, FOLDER(list->data));
1032 static gchar *get_scan_str(FolderItem *item)
1035 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1036 item->folder->name, G_DIR_SEPARATOR,
1039 return g_strdup_printf(_("Scanning folder %s ..."),
1040 item->folder->name);
1042 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1046 for (list = folderview_list; list != NULL; list = list->next) {
1047 FolderView *folderview = (FolderView *)list->data;
1048 MainWindow *mainwin = folderview->mainwin;
1049 gchar *str = get_scan_str(item);
1051 STATUSBAR_PUSH(mainwin, str);
1052 STATUSBAR_POP(mainwin);
1057 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1061 g_return_if_fail(folder != NULL);
1063 if (!folder->klass->scan_tree) return;
1066 alertpanel_full(_("Rebuild folder tree"),
1067 _("Rebuilding the folder tree will remove "
1068 "local caches. Do you want to continue?"),
1069 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1070 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1071 != G_ALERTALTERNATE) {
1077 window = label_window_create(_("Rebuilding folder tree..."));
1079 window = label_window_create(_("Scanning folder tree..."));
1081 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1082 folder_scan_tree(folder, rebuild);
1083 folder_set_ui_func(folder, NULL, NULL);
1085 folderview_set_all();
1087 gtk_widget_destroy(window);
1091 /** folderview_check_new()
1092 * Scan and update the folder and return the
1093 * count the number of new messages since last check.
1094 * \param folder the folder to check for new messages
1095 * \return the number of new messages since last check
1097 gint folderview_check_new(Folder *folder)
1101 FolderView *folderview;
1105 gint former_new_msgs = 0;
1106 gint former_new = 0, former_unread = 0, former_total;
1108 for (list = folderview_list; list != NULL; list = list->next) {
1109 folderview = (FolderView *)list->data;
1110 ctree = GTK_CTREE(folderview->ctree);
1113 main_window_lock(folderview->mainwin);
1115 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1116 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1118 item = gtk_ctree_node_get_row_data(ctree, node);
1119 if (!item || !item->path || !item->folder) continue;
1120 if (item->no_select) continue;
1121 if (folder && folder != item->folder) continue;
1122 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1123 if (!item->prefs->newmailcheck) continue;
1124 if (item->processing_pending == TRUE) {
1125 debug_print("skipping %s, processing pending\n",
1126 item->path ? item->path : item->name);
1130 str = get_scan_str(item);
1132 STATUSBAR_PUSH(folderview->mainwin, str);
1136 folderview_scan_tree_func(item->folder, item, NULL);
1137 former_new = item->new_msgs;
1138 former_unread = item->unread_msgs;
1139 former_total = item->total_msgs;
1141 if (item->folder->klass->scan_required &&
1142 (item->folder->klass->scan_required(item->folder, item) ||
1143 item->folder->inbox == item ||
1144 item->opened == TRUE ||
1145 item->processing_pending == TRUE)) {
1146 if (folder_item_scan(item) < 0) {
1147 summaryview_unlock(folderview->summaryview, item);
1148 if (folder && !FOLDER_IS_LOCAL(folder)) {
1149 STATUSBAR_POP(folderview->mainwin);
1153 } else if (!item->folder->klass->scan_required) {
1154 if (folder_item_scan(item) < 0) {
1155 summaryview_unlock(folderview->summaryview, item);
1156 if (folder && !FOLDER_IS_LOCAL(folder)) {
1157 STATUSBAR_POP(folderview->mainwin);
1162 if (former_new != item->new_msgs ||
1163 former_unread != item->unread_msgs ||
1164 former_total != item->total_msgs)
1165 folderview_update_node(folderview, node);
1167 new_msgs += item->new_msgs;
1168 former_new_msgs += former_new;
1169 STATUSBAR_POP(folderview->mainwin);
1172 main_window_unlock(folderview->mainwin);
1176 folder_write_list();
1177 /* Number of new messages since last check is the just the difference
1178 * between former_new_msgs and new_msgs. If new_msgs is less than
1179 * former_new_msgs, that would mean another session accessed the folder
1180 * and the result is not well defined.
1182 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1186 void folderview_check_new_all(void)
1190 FolderView *folderview;
1192 folderview = (FolderView *)folderview_list->data;
1195 main_window_lock(folderview->mainwin);
1196 window = label_window_create
1197 (_("Checking for new messages in all folders..."));
1199 list = folder_get_list();
1200 for (; list != NULL; list = list->next) {
1201 Folder *folder = list->data;
1203 folderview_check_new(folder);
1206 folder_write_list();
1207 folderview_set_all();
1209 gtk_widget_destroy(window);
1210 main_window_unlock(folderview->mainwin);
1214 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1220 if (!item || !item->folder || !item->folder->node)
1223 node = item->folder->node;
1225 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1226 node = node->children;
1229 (item->new_msgs > 0 ||
1230 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1234 while (node != NULL) {
1235 if (node && node->data) {
1236 FolderItem *next_item = (FolderItem*) node->data;
1238 if (folderview_have_new_children_sub(folderview,
1247 static gboolean folderview_have_new_children(FolderView *folderview,
1250 return folderview_have_new_children_sub(folderview, item, FALSE);
1253 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1259 if (!item || !item->folder || !item->folder->node)
1262 node = item->folder->node;
1264 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1265 node = node->children;
1268 (item->unread_msgs > 0 ||
1269 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1273 while (node != NULL) {
1274 if (node && node->data) {
1275 FolderItem *next_item = (FolderItem*) node->data;
1277 if (folderview_have_unread_children_sub(folderview,
1287 static gboolean folderview_have_unread_children(FolderView *folderview,
1290 return folderview_have_unread_children_sub(folderview, item, FALSE);
1293 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1299 if (!item || !item->folder || !item->folder->node)
1302 node = item->folder->node;
1304 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1305 node = node->children;
1307 if (in_sub && item->search_match){
1311 while (node != NULL) {
1312 if (node && node->data) {
1313 FolderItem *next_item = (FolderItem*) node->data;
1315 if (folderview_have_matching_children_sub(folderview,
1325 static gboolean folderview_have_matching_children(FolderView *folderview,
1328 return folderview_have_matching_children_sub(folderview, item, FALSE);
1331 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1337 if (!item || !item->folder || !item->folder->node)
1340 node = item->folder->node;
1342 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1343 node = node->children;
1345 if (item->marked_msgs != 0) {
1349 while (node != NULL) {
1350 if (node && node->data) {
1351 FolderItem *next_item = (FolderItem*) node->data;
1353 if (folderview_have_marked_children_sub(folderview,
1362 static gboolean folderview_have_marked_children(FolderView *folderview,
1365 return folderview_have_marked_children_sub(folderview, item, FALSE);
1368 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1370 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1371 GtkStyle *style = NULL;
1372 GtkStyle *color_style = NULL;
1374 GdkPixmap *xpm, *openxpm;
1375 GdkBitmap *mask, *openmask;
1376 static GdkPixmap *searchicon;
1377 static GdkBitmap *searchmask;
1378 gboolean mark = FALSE;
1381 gboolean add_unread_mark;
1382 gboolean add_sub_match_mark;
1383 gboolean use_bold, use_color;
1384 gint *col_pos = folderview->col_pos;
1385 SpecialFolderItemType stype;
1387 item = gtk_ctree_node_get_row_data(ctree, node);
1388 g_return_if_fail(item != NULL);
1390 if (!GTK_CTREE_ROW(node)->expanded)
1391 mark = folderview_have_marked_children(folderview, item);
1393 mark = (item->marked_msgs != 0);
1395 stype = item->stype;
1396 if (stype == F_NORMAL) {
1397 if (folder_has_parent_of_type(item, F_TRASH))
1399 else if (folder_has_parent_of_type(item, F_DRAFT))
1401 else if (folder_has_parent_of_type(item, F_OUTBOX))
1403 else if (folder_has_parent_of_type(item, F_QUEUE))
1408 if (item->hide_read_msgs) {
1409 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1410 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1411 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1412 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1414 xpm = mark?m_inboxxpm:inboxxpm;
1415 mask = mark?m_inboxxpmmask:inboxxpmmask;
1416 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1417 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1421 if (item->hide_read_msgs) {
1422 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1423 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1424 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1425 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1427 xpm = mark?m_outboxxpm:outboxxpm;
1428 mask = mark?m_outboxxpmmask:outboxxpmmask;
1429 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1430 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1434 if (item->hide_read_msgs) {
1435 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1436 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1437 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1438 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1440 xpm = mark?m_queuexpm:queuexpm;
1441 mask = mark?m_queuexpmmask:queuexpmmask;
1442 openxpm = mark?m_queueopenxpm:queueopenxpm;
1443 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1447 if (item->hide_read_msgs) {
1448 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1449 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1450 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1451 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1453 xpm = mark?m_trashxpm:trashxpm;
1454 mask = mark?m_trashxpmmask:trashxpmmask;
1455 openxpm = mark?m_trashopenxpm:trashopenxpm;
1456 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1460 xpm = mark?m_draftsxpm:draftsxpm;
1461 mask = mark?m_draftsxpmmask:draftsxpmmask;
1462 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1463 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1466 if (item->hide_read_msgs) {
1467 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1468 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1469 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1470 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1472 xpm = mark?m_folderxpm:folderxpm;
1473 mask = mark?m_folderxpmmask:folderxpmmask;
1474 openxpm = mark?m_folderopenxpm:folderopenxpm;
1475 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1479 if (item->no_select) {
1480 xpm = openxpm = noselectxpm;
1481 mask = openmask = noselectxpmmask;
1484 name = folder_item_get_name(item);
1486 if (!GTK_CTREE_ROW(node)->expanded) {
1487 add_unread_mark = folderview_have_unread_children(
1489 add_sub_match_mark = folderview_have_matching_children(
1492 add_unread_mark = FALSE;
1493 add_sub_match_mark = FALSE;
1496 if (item->search_match) {
1498 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1499 &searchicon, &searchmask);
1501 xpm = openxpm = searchicon;
1502 mask = openmask = searchmask;
1505 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1506 prefs_common.display_folder_unread) {
1507 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1508 add_unread_mark ? "+" : "");
1509 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1510 xpm, mask, openxpm, openmask,
1511 FALSE, GTK_CTREE_ROW(node)->expanded);
1513 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1514 prefs_common.display_folder_unread)
1515 || add_sub_match_mark) {
1517 if (item->unread_msgs > 0)
1518 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1519 add_unread_mark || add_sub_match_mark ? "+" : "",
1520 item->unreadmarked_msgs > 0 ? "!":"");
1522 str = g_strdup_printf("%s (+)", name);
1523 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1524 xpm, mask, openxpm, openmask,
1525 FALSE, GTK_CTREE_ROW(node)->expanded);
1528 str = g_strdup_printf("%s%s", name,
1529 item->unreadmarked_msgs > 0 ? " (!)":"");
1531 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1532 xpm, mask, openxpm, openmask,
1533 FALSE, GTK_CTREE_ROW(node)->expanded);
1538 if (!folder_item_parent(item)) {
1539 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1540 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1541 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1543 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1544 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1545 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1548 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1549 folder_has_parent_of_type(item, F_DRAFT) ||
1550 folder_has_parent_of_type(item, F_TRASH)) {
1551 use_bold = use_color = FALSE;
1552 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1553 /* highlight queue folder if there are any messages */
1554 use_bold = use_color = (item->total_msgs > 0);
1556 /* if unread messages exist, print with bold font */
1557 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1559 /* if new messages exist, print with colored letter */
1561 (item->new_msgs > 0) ||
1563 folderview_have_new_children(folderview, item));
1566 gtk_ctree_node_set_foreground(ctree, node, NULL);
1571 if (item->prefs->color > 0 && !use_color) {
1572 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1573 color_style = gtk_style_copy(bold_style);
1574 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1575 style = color_style;
1576 } else if (use_color) {
1577 style = bold_color_style;
1580 if (item->op_count > 0) {
1581 style = bold_tgtfold_style;
1583 } else if (use_color) {
1584 style = normal_color_style;
1585 gtk_ctree_node_set_foreground(ctree, node,
1586 &folderview->color_new);
1587 } else if (item->op_count > 0) {
1588 style = bold_tgtfold_style;
1589 } else if (item->prefs->color > 0) {
1591 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1592 color_style = gtk_style_copy(normal_style);
1593 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1594 style = color_style;
1596 style = normal_style;
1599 gtk_ctree_node_set_row_style(ctree, node, style);
1601 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1602 folderview_update_node(folderview, node);
1605 #if !CLAWS /* keep it here for syncs */
1606 void folderview_update_item(FolderItem *item, gboolean update_summary)
1609 FolderView *folderview;
1613 g_return_if_fail(item != NULL);
1615 for (list = folderview_list; list != NULL; list = list->next) {
1616 folderview = (FolderView *)list->data;
1617 ctree = GTK_CTREE(folderview->ctree);
1619 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1621 folderview_update_node(folderview, node);
1622 if (update_summary && folderview->opened == node)
1623 summary_show(folderview->summaryview,
1630 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1633 FolderView *folderview;
1637 g_return_if_fail(item != NULL);
1639 for (list = folderview_list; list != NULL; list = list->next) {
1640 folderview = (FolderView *)list->data;
1641 ctree = GTK_CTREE(folderview->ctree);
1643 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1645 item->search_match = matches;
1646 folderview_update_node(folderview, node);
1651 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1653 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1654 FolderView *folderview = (FolderView *)data;
1657 g_return_val_if_fail(update_info != NULL, TRUE);
1658 g_return_val_if_fail(update_info->item != NULL, TRUE);
1659 g_return_val_if_fail(folderview != NULL, FALSE);
1661 ctree = GTK_CTREE(folderview->ctree);
1663 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1665 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1666 folderview_update_node(folderview, node);
1667 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1668 summary_show(folderview->summaryview, update_info->item);
1674 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1677 /* CLAWS: share this joy with other hook functions ... */
1678 folder_item_update((FolderItem *)key,
1679 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1682 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1685 FolderItemUpdateFlags flags;
1687 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1689 for (list = folderview_list; list != NULL; list = list->next)
1690 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1691 GINT_TO_POINTER(flags));
1694 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1695 GNode *gnode, GtkCTreeNode *cnode,
1698 FolderView *folderview = (FolderView *)data;
1699 FolderItem *item = FOLDER_ITEM(gnode->data);
1701 g_return_val_if_fail(item != NULL, FALSE);
1703 gtk_ctree_node_set_row_data(ctree, cnode, item);
1704 folderview_update_node(folderview, cnode);
1709 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1712 FolderView *folderview = (FolderView *)data;
1715 if (GTK_CTREE_ROW(node)->children) {
1716 item = gtk_ctree_node_get_row_data(ctree, node);
1717 g_return_if_fail(item != NULL);
1719 if (!item->collapsed)
1720 gtk_ctree_expand(ctree, node);
1722 folderview_update_node(folderview, node);
1726 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1727 GtkCTreeNode *root, GtkCTreeNode **prev)
1730 GtkCTreeNode *node, *parent, *sibling;
1732 node = gtk_ctree_find_by_row_data(ctree, root, item);
1734 g_warning("%s not found.\n", item->path);
1736 parent = GTK_CTREE_ROW(node)->parent;
1737 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1738 sibling = GTK_CTREE_ROW(*prev)->sibling;
1740 sibling = GTK_CTREE_ROW(parent)->children;
1744 tmp = gtk_ctree_node_get_row_data
1746 if (tmp->stype != F_NORMAL)
1747 sibling = GTK_CTREE_ROW(sibling)->sibling;
1751 if (node != sibling)
1752 gtk_ctree_move(ctree, node, parent, sibling);
1759 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1762 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1763 GtkCTreeNode *prev = NULL;
1765 gtk_sctree_sort_recursive(ctree, root);
1767 if (root && GTK_CTREE_ROW(root)->parent) return;
1769 set_special_folder(ctree, folder->inbox, root, &prev);
1770 set_special_folder(ctree, folder->outbox, root, &prev);
1771 set_special_folder(ctree, folder->draft, root, &prev);
1772 set_special_folder(ctree, folder->queue, root, &prev);
1773 set_special_folder(ctree, folder->trash, root, &prev);
1776 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1778 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1781 g_return_if_fail(folder != NULL);
1783 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1784 folderview_gnode_func, folderview);
1785 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1787 folderview_sort_folders(folderview, root, folder);
1790 /* callback functions */
1792 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1793 FolderView *folderview)
1795 GtkCList *clist = GTK_CLIST(ctree);
1796 gint prev_row = -1, row = -1, column = -1;
1799 FolderViewPopup *fpopup;
1800 GtkItemFactory *fpopup_factory;
1802 FolderItem *special_trash = NULL, *special_queue = NULL;
1805 if (!event) return FALSE;
1807 if (event->button == 1 || event->button == 2) {
1808 folderview->open_folder = TRUE;
1810 if (event->type == GDK_2BUTTON_PRESS) {
1811 if (clist->selection) {
1814 node = GTK_CTREE_NODE(clist->selection->data);
1816 gtk_ctree_toggle_expansion(
1824 if (event->button == 2 || event->button == 3) {
1826 if (clist->selection) {
1829 node = GTK_CTREE_NODE(clist->selection->data);
1831 prev_row = gtkut_ctree_get_nth_from_node
1832 (GTK_CTREE(ctree), node);
1835 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1838 if (prev_row != row) {
1839 gtk_clist_unselect_all(clist);
1840 if (event->button == 2)
1841 folderview_select_node
1843 gtk_ctree_node_nth(GTK_CTREE(ctree),
1846 gtk_clist_select_row(clist, row, column);
1850 if (event->button != 3) return FALSE;
1852 item = gtk_clist_get_row_data(clist, row);
1853 g_return_val_if_fail(item != NULL, FALSE);
1854 g_return_val_if_fail(item->folder != NULL, FALSE);
1855 folder = item->folder;
1857 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1859 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1861 fpopup = g_hash_table_lookup(folderview_popups, "common");
1862 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1865 if (fpopup->set_sensitivity != NULL)
1866 fpopup->set_sensitivity(fpopup_factory, item);
1868 if (NULL != (ac = account_find_from_item(item))) {
1869 special_trash = account_get_special_folder(ac, F_TRASH);
1870 special_queue = account_get_special_folder(ac, F_QUEUE);
1873 if ((item == folder->trash || item == special_trash
1874 || folder_has_parent_of_type(item, F_TRASH)) &&
1875 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1876 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1877 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1878 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1879 && !folder_has_parent_of_type(item, F_TRASH)) {
1880 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1881 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1884 if ((item == folder->queue || item == special_queue
1885 || folder_has_parent_of_type(item, F_QUEUE)) &&
1886 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1887 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1888 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1889 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1890 && !folder_has_parent_of_type(item, F_QUEUE)) {
1891 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1892 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1895 #define SET_SENS(name, sens) \
1896 menu_set_sensitive(fpopup_factory, name, sens)
1898 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1899 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1900 folderview->selected == folderview->opened);
1901 SET_SENS("/Properties...", TRUE);
1902 SET_SENS("/Processing...", item->node->parent != NULL);
1903 if (item == folder->trash || item == special_trash
1904 || folder_has_parent_of_type(item, F_TRASH)) {
1905 GSList *msglist = folder_item_get_msg_list(item);
1906 SET_SENS("/Empty trash...", msglist != NULL);
1907 procmsg_msg_list_free(msglist);
1909 if (item == folder->queue || item == special_queue
1910 || folder_has_parent_of_type(item, F_QUEUE)) {
1911 GSList *msglist = folder_item_get_msg_list(item);
1912 SET_SENS("/Send queue...", msglist != NULL);
1913 procmsg_msg_list_free(msglist);
1917 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1918 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1919 event->button, event->time);
1924 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1925 FolderView *folderview)
1927 if (!event) return FALSE;
1929 if (event->button == 1 && folderview->open_folder == FALSE &&
1930 folderview->opened != NULL) {
1931 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1932 folderview->opened);
1933 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1939 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1940 FolderView *folderview)
1942 if (!event) return FALSE;
1944 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1947 switch (event->keyval) {
1949 if (folderview->selected) {
1950 folderview_select_node(folderview,
1951 folderview->selected);
1955 if (folderview->selected) {
1956 if (folderview->opened == folderview->selected &&
1957 (!folderview->summaryview->folder_item ||
1958 folderview->summaryview->folder_item->total_msgs == 0))
1959 folderview_select_next_unread(folderview);
1961 folderview_select_node(folderview,
1962 folderview->selected);
1972 typedef struct _PostponedSelectData
1977 FolderView *folderview;
1978 } PostponedSelectData;
1980 static gboolean postpone_select(void *data)
1982 PostponedSelectData *psdata = (PostponedSelectData *)data;
1983 debug_print("trying again\n");
1984 psdata->folderview->open_folder = TRUE;
1985 main_window_cursor_normal(psdata->folderview->mainwin);
1986 STATUSBAR_POP(psdata->folderview->mainwin);
1987 folderview_selected(psdata->ctree, psdata->row,
1988 psdata->column, psdata->folderview);
1993 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1994 gint column, FolderView *folderview)
1996 static gboolean can_select = TRUE; /* exclusive lock */
2002 folderview->selected = row;
2004 if (folderview->opened == row) {
2005 folderview->open_folder = FALSE;
2009 if (!can_select || summary_is_locked(folderview->summaryview)) {
2010 if (folderview->opened) {
2011 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2012 gtk_ctree_select(ctree, folderview->opened);
2017 if (!folderview->open_folder) return;
2019 item = gtk_ctree_node_get_row_data(ctree, row);
2020 if (!item || item->no_select) return;
2024 /* Save cache for old folder */
2025 /* We don't want to lose all caches if sylpheed crashed */
2026 if (folderview->opened) {
2027 FolderItem *olditem;
2029 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2031 buf = g_strdup_printf(_("Closing Folder %s..."),
2032 olditem->path ? olditem->path:olditem->name);
2033 /* will be null if we just moved the previously opened folder */
2034 STATUSBAR_PUSH(folderview->mainwin, buf);
2035 main_window_cursor_wait(folderview->mainwin);
2037 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2038 summary_show(folderview->summaryview, NULL);
2039 folder_item_close(olditem);
2040 main_window_cursor_normal(folderview->mainwin);
2041 STATUSBAR_POP(folderview->mainwin);
2045 /* CLAWS: set compose button type: news folder items
2046 * always have a news folder as parent */
2048 toolbar_set_compose_button
2049 (folderview->mainwin->toolbar,
2050 FOLDER_TYPE(item->folder) == F_NEWS ?
2051 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2054 debug_print("Folder %s is selected\n", item->path);
2056 if (!GTK_CTREE_ROW(row)->children)
2057 gtk_ctree_expand(ctree, row);
2058 if (folderview->opened &&
2059 !GTK_CTREE_ROW(folderview->opened)->children)
2060 gtk_ctree_collapse(ctree, folderview->opened);
2062 /* ungrab the mouse event */
2063 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2064 gtk_grab_remove(GTK_WIDGET(ctree));
2065 if (gdk_pointer_is_grabbed())
2066 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2070 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2071 item->path : "(null)");
2072 debug_print("%s\n", buf);
2073 STATUSBAR_PUSH(folderview->mainwin, buf);
2076 main_window_cursor_wait(folderview->mainwin);
2078 res = folder_item_open(item);
2080 main_window_cursor_normal(folderview->mainwin);
2081 STATUSBAR_POP(folderview->mainwin);
2083 alertpanel_error(_("Folder could not be opened."));
2085 folderview->open_folder = FALSE;
2089 } else if (res == -2) {
2090 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2091 data->ctree = ctree;
2093 data->column = column;
2094 data->folderview = folderview;
2095 debug_print("postponing open of %s till end of scan\n",
2096 item->path ? item->path:item->name);
2097 folderview->open_folder = FALSE;
2099 g_timeout_add(500, postpone_select, data);
2103 main_window_cursor_normal(folderview->mainwin);
2106 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2107 opened = summary_show(folderview->summaryview, item);
2109 folder_clean_cache_memory(item);
2112 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2113 gtk_ctree_select(ctree, folderview->opened);
2115 folderview->opened = row;
2116 if (gtk_ctree_node_is_visible(ctree, row)
2117 != GTK_VISIBILITY_FULL)
2118 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2121 STATUSBAR_POP(folderview->mainwin);
2123 folderview->open_folder = FALSE;
2127 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2128 FolderView *folderview)
2132 item = gtk_ctree_node_get_row_data(ctree, node);
2133 g_return_if_fail(item != NULL);
2134 item->collapsed = FALSE;
2135 folderview_update_node(folderview, node);
2138 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2139 FolderView *folderview)
2143 item = gtk_ctree_node_get_row_data(ctree, node);
2144 g_return_if_fail(item != NULL);
2145 item->collapsed = TRUE;
2146 folderview_update_node(folderview, node);
2149 static void folderview_popup_close(GtkMenuShell *menu_shell,
2150 FolderView *folderview)
2152 if (!folderview->opened) return;
2154 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2157 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2158 FolderView *folderview)
2160 FolderColumnType type = folderview->col_state[column].type;
2162 prefs_common.folder_col_size[type] = width;
2165 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2169 folderview_create_folder_node(folderview, item);
2171 if (!item || !item->folder || !item->folder->node)
2174 srcnode = item->folder->node;
2175 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2176 srcnode = srcnode->children;
2177 while (srcnode != NULL) {
2178 if (srcnode && srcnode->data) {
2179 FolderItem *next_item = (FolderItem*) srcnode->data;
2180 folderview_create_folder_node_recursive(folderview, next_item);
2182 srcnode = srcnode->next;
2186 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2188 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2189 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2190 GtkCTreeNode *node, *parent_node;
2191 gint *col_pos = folderview->col_pos;
2192 FolderItemUpdateData hookdata;
2194 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2195 if (parent_node == NULL)
2198 gtk_clist_freeze(GTK_CLIST(ctree));
2200 text[col_pos[F_COL_FOLDER]] = item->name;
2201 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2203 folderxpm, folderxpmmask,
2204 folderopenxpm, folderopenxpmmask,
2206 gtk_ctree_expand(ctree, parent_node);
2207 gtk_ctree_node_set_row_data(ctree, node, item);
2209 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2210 folderview_sort_folders(folderview, parent_node, item->folder);
2212 hookdata.item = item;
2213 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2214 hookdata.msg = NULL;
2215 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2217 gtk_clist_thaw(GTK_CLIST(ctree));
2220 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2223 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2225 GSList *mlist = NULL;
2227 FolderItem *special_trash = NULL;
2230 if (!folderview->selected) return;
2231 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2232 g_return_if_fail(item != NULL);
2233 g_return_if_fail(item->folder != NULL);
2235 if (NULL != (ac = account_find_from_item(item)))
2236 special_trash = account_get_special_folder(ac, F_TRASH);
2238 if (item != item->folder->trash && item != special_trash
2239 && !folder_has_parent_of_type(item, F_TRASH)) return;
2241 if (prefs_common.ask_on_clean) {
2242 if (alertpanel(_("Empty trash"),
2243 _("Delete all messages in trash?"),
2244 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2248 mlist = folder_item_get_msg_list(item);
2250 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2251 MsgInfo * msginfo = (MsgInfo *) cur->data;
2252 if (MSG_IS_LOCKED(msginfo->flags))
2254 /* is it partially received? (partial_recv isn't cached) */
2255 if (msginfo->total_size != 0 &&
2256 msginfo->size != (off_t)msginfo->total_size)
2257 partial_mark_for_delete(msginfo);
2259 procmsg_msg_list_free(mlist);
2261 folder_item_remove_all_msg(item);
2264 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2267 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2269 FolderItem *special_queue = NULL;
2271 gchar *errstr = NULL;
2273 if (!folderview->selected) return;
2274 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2275 g_return_if_fail(item != NULL);
2276 g_return_if_fail(item->folder != NULL);
2278 if (NULL != (ac = account_find_from_item(item)))
2279 special_queue = account_get_special_folder(ac, F_QUEUE);
2281 if (item != item->folder->queue && item != special_queue
2282 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2284 if (procmsg_queue_is_empty(item))
2287 if (prefs_common.work_offline)
2288 if (alertpanel(_("Offline warning"),
2289 _("You're working offline. Override?"),
2290 GTK_STOCK_NO, GTK_STOCK_YES,
2291 NULL) != G_ALERTALTERNATE)
2294 /* ask for confirmation before sending queued messages only
2295 in online mode and if there is at least one message queued
2296 in any of the folder queue
2298 if (prefs_common.confirm_send_queued_messages) {
2299 if (!prefs_common.work_offline) {
2300 if (alertpanel(_("Send queued messages"),
2301 _("Send all queued messages?"),
2302 GTK_STOCK_CANCEL, _("_Send"),
2303 NULL) != G_ALERTALTERNATE)
2308 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2310 alertpanel_error_log(_("Some errors occurred while "
2311 "sending queued messages."));
2313 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2314 "while sending queued messages:\n%s"), errstr);
2316 alertpanel_error_log(tmp);
2322 static void folderview_search_cb(FolderView *folderview, guint action,
2325 summary_search(folderview->summaryview);
2328 static void folderview_property_cb(FolderView *folderview, guint action,
2331 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2334 if (!folderview->selected) return;
2336 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2337 g_return_if_fail(item != NULL);
2338 g_return_if_fail(item->folder != NULL);
2340 prefs_folder_item_open(item);
2343 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2345 GSList *list = NULL;
2346 GSList *done = NULL;
2347 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2349 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2350 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2351 && list->data != node) {
2352 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2353 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2356 for (list = done; list != NULL; list = g_slist_next(list)) {
2357 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2363 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2364 FolderItem *to_folder)
2366 FolderItem *from_parent = NULL;
2367 FolderItem *new_folder = NULL;
2368 GtkCTreeNode *src_node = NULL;
2372 g_return_if_fail(folderview != NULL);
2373 g_return_if_fail(from_folder != NULL);
2374 g_return_if_fail(to_folder != NULL);
2376 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2377 from_parent = folder_item_parent(from_folder);
2379 if (prefs_common.warn_dnd) {
2380 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2381 "sub-folder of '%s' ?"), from_folder->name,
2383 status = alertpanel_full(_("Move folder"), buf,
2384 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2385 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2388 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2390 else if (status & G_ALERTDISABLE)
2391 prefs_common.warn_dnd = FALSE;
2394 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2395 STATUSBAR_PUSH(folderview->mainwin, buf);
2397 summary_clear_all(folderview->summaryview);
2398 folderview->opened = NULL;
2399 folderview->selected = NULL;
2400 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2402 main_window_cursor_wait(folderview->mainwin);
2403 statusbar_verbosity_set(TRUE);
2404 folder_item_update_freeze();
2405 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2406 statusbar_verbosity_set(FALSE);
2407 main_window_cursor_normal(folderview->mainwin);
2408 STATUSBAR_POP(folderview->mainwin);
2409 folder_item_update_thaw();
2410 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2412 folderview_sort_folders(folderview,
2413 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2414 NULL, to_folder), new_folder->folder);
2415 folderview_select(folderview, new_folder);
2417 statusbar_verbosity_set(FALSE);
2418 main_window_cursor_normal(folderview->mainwin);
2419 STATUSBAR_POP(folderview->mainwin);
2420 folder_item_update_thaw();
2422 case F_MOVE_FAILED_DEST_IS_PARENT:
2423 alertpanel_error(_("Source and destination are the same."));
2425 case F_MOVE_FAILED_DEST_IS_CHILD:
2426 alertpanel_error(_("Can't move a folder to one of its children."));
2428 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2429 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2432 alertpanel_error(_("Move failed!"));
2437 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2440 static gint folderview_clist_compare(GtkCList *clist,
2441 gconstpointer ptr1, gconstpointer ptr2)
2443 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2444 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2447 return (item2->name != NULL);
2451 return g_utf8_collate(item1->name, item2->name);
2454 static void folderview_processing_cb(FolderView *folderview, guint action,
2457 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2461 if (!folderview->selected) return;
2463 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2464 g_return_if_fail(item != NULL);
2465 g_return_if_fail(item->folder != NULL);
2467 id = folder_item_get_identifier(item);
2468 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2471 prefs_filtering_open(&item->prefs->processing, title,
2472 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2476 void folderview_set_target_folder_color(gint color_op)
2480 FolderView *folderview;
2482 for (list = folderview_list; list != NULL; list = list->next) {
2483 folderview = (FolderView *)list->data;
2484 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2486 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2487 folderview->color_op;
2493 static gchar *last_font = NULL;
2494 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2502 void folderview_reflect_prefs(void)
2504 gboolean update_font = TRUE;
2505 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2506 FolderItem *item = folderview_get_selected_item(folderview);
2507 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2508 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2509 gint height = pos->value;
2511 if (last_font && !strcmp(last_font, NORMAL_FONT))
2512 update_font = FALSE;
2515 last_font = g_strdup(NORMAL_FONT);
2518 normal_style = normal_color_style = bold_style =
2519 bold_color_style = bold_tgtfold_style = NULL;
2521 folderview_init(folderview);
2523 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2524 folderview_column_set_titles(folderview);
2525 folderview_set_all();
2527 g_signal_handlers_block_by_func
2528 (G_OBJECT(folderview->ctree),
2529 G_CALLBACK(folderview_selected), folderview);
2532 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2533 GTK_CTREE(folderview->ctree), NULL, item);
2535 folderview_select(folderview, item);
2536 folderview->selected = node;
2539 g_signal_handlers_unblock_by_func
2540 (G_OBJECT(folderview->ctree),
2541 G_CALLBACK(folderview_selected), folderview);
2543 pos = gtk_scrolled_window_get_vadjustment(
2544 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2545 gtk_adjustment_set_value(pos, height);
2546 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2549 static void drag_state_stop(FolderView *folderview)
2551 if (folderview->drag_timer)
2552 gtk_timeout_remove(folderview->drag_timer);
2553 folderview->drag_timer = 0;
2554 folderview->drag_node = NULL;
2557 static gint folderview_defer_expand(FolderView *folderview)
2559 if (folderview->drag_node) {
2560 folderview_recollapse_nodes(folderview, folderview->drag_node);
2561 if (folderview->drag_item->collapsed) {
2562 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2563 folderview->nodes_to_recollapse = g_slist_append
2564 (folderview->nodes_to_recollapse, folderview->drag_node);
2567 folderview->drag_item = NULL;
2568 folderview->drag_timer = 0;
2572 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2574 /* the idea is that we call drag_state_start() whenever we want expansion to
2575 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2576 * we need to call drag_state_stop() */
2577 drag_state_stop(folderview);
2578 /* request expansion */
2579 if (0 != (folderview->drag_timer = gtk_timeout_add
2580 (prefs_common.hover_timeout,
2581 (GtkFunction)folderview_defer_expand,
2583 folderview->drag_node = node;
2584 folderview->drag_item = item;
2588 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2589 FolderView *folderview)
2591 GdkDragContext *context;
2593 g_return_if_fail(folderview != NULL);
2594 if (folderview->selected == NULL) return;
2595 if (folderview->nodes_to_recollapse)
2596 g_slist_free(folderview->nodes_to_recollapse);
2597 folderview->nodes_to_recollapse = NULL;
2598 context = gtk_drag_begin(widget, folderview->target_list,
2599 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2600 gtk_drag_set_icon_default(context);
2603 static void folderview_drag_data_get(GtkWidget *widget,
2604 GdkDragContext *drag_context,
2605 GtkSelectionData *selection_data,
2608 FolderView *folderview)
2612 gchar *source = NULL;
2613 if (info == TARGET_DUMMY) {
2614 for (cur = GTK_CLIST(folderview->ctree)->selection;
2615 cur != NULL; cur = cur->next) {
2616 item = gtk_ctree_node_get_row_data
2617 (GTK_CTREE(folderview->ctree),
2618 GTK_CTREE_NODE(cur->data));
2620 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2621 gtk_selection_data_set(selection_data,
2622 selection_data->target, 8,
2623 source, strlen(source));
2629 g_warning("unknown info %d\n", info);
2633 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2635 FolderUpdateData *hookdata;
2636 FolderView *folderview;
2640 folderview = (FolderView *) userdata;
2641 g_return_val_if_fail(hookdata != NULL, FALSE);
2642 g_return_val_if_fail(folderview != NULL, FALSE);
2644 ctree = folderview->ctree;
2645 g_return_val_if_fail(ctree != NULL, FALSE);
2647 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2648 folderview_create_folder_node(folderview, hookdata->item);
2649 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2650 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2651 NULL, folder_item_parent(hookdata->item));
2652 folderview_sort_folders(folderview, node, hookdata->folder);
2653 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2656 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2658 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2659 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2660 folderview_set(folderview);
2665 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2666 GdkDragContext *context,
2670 FolderView *folderview)
2673 FolderItem *item = NULL, *src_item = NULL;
2674 GtkCTreeNode *node = NULL;
2675 gboolean acceptable = FALSE;
2676 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2677 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2678 int height = (int)pos->page_size;
2679 int total_height = (int)pos->upper;
2680 int vpos = (int) pos->value;
2682 if (gtk_clist_get_selection_info
2683 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2684 GtkWidget *srcwidget;
2686 if (y > height - 24 && height + vpos < total_height)
2687 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2689 if (y < 48 && y > 0)
2690 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2692 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2693 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2694 src_item = folderview->summaryview->folder_item;
2696 srcwidget = gtk_drag_get_source_widget(context);
2697 if (srcwidget == folderview->summaryview->ctree) {
2698 /* comes from summaryview */
2699 /* we are copying messages, so only accept folder items that are not
2700 the source item, are no root items and can copy messages */
2701 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2702 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2704 } else if (srcwidget == folderview->ctree) {
2705 /* comes from folderview */
2706 /* we are moving folder items, only accept folders that are not
2707 the source items and can copy messages and create folder items */
2708 if (item && item->folder && src_item && src_item != item &&
2709 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2710 FOLDER_CLASS(item->folder)->create_folder != NULL)
2713 /* comes from another app */
2714 /* we are adding messages, so only accept folder items that are
2715 no root items and can copy messages */
2716 if (item && item->folder && folder_item_parent(item) != NULL
2717 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2722 if (acceptable || (src_item && src_item == item))
2723 drag_state_start(folderview, node, item);
2726 g_signal_handlers_block_by_func
2728 G_CALLBACK(folderview_selected), folderview);
2729 gtk_ctree_select(GTK_CTREE(widget), node);
2730 g_signal_handlers_unblock_by_func
2732 G_CALLBACK(folderview_selected), folderview);
2733 gdk_drag_status(context,
2734 (context->actions == GDK_ACTION_COPY ?
2735 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2737 if (folderview->opened)
2738 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2739 gdk_drag_status(context, 0, time);
2745 static void folderview_drag_leave_cb(GtkWidget *widget,
2746 GdkDragContext *context,
2748 FolderView *folderview)
2750 drag_state_stop(folderview);
2751 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2754 static void free_info (gpointer stuff, gpointer data)
2759 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2760 guint time, FolderItem *item)
2763 GSList *msglist = NULL;
2764 list = uri_list_extract_filenames(data);
2765 if (!(item && item->folder && folder_item_parent(item) != NULL
2766 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2768 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2772 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2775 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2776 MsgFileInfo *info = NULL;
2778 if (file_is_email((gchar *)tmp->data)) {
2779 info = g_new0(MsgFileInfo, 1);
2780 info->msginfo = NULL;
2781 info->file = (gchar *)tmp->data;
2782 msglist = g_slist_prepend(msglist, info);
2786 msglist = g_slist_reverse(msglist);
2787 folder_item_add_msgs(item, msglist, FALSE);
2788 g_slist_foreach(msglist, free_info, NULL);
2789 g_slist_free(msglist);
2790 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2792 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2794 list_free_strings(list);
2798 static void folderview_drag_received_cb(GtkWidget *widget,
2799 GdkDragContext *drag_context,
2802 GtkSelectionData *data,
2805 FolderView *folderview)
2808 FolderItem *item = NULL, *src_item;
2811 if (info == TARGET_DUMMY) {
2812 drag_state_stop(folderview);
2813 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2814 /* comes from summaryview */
2815 if (gtk_clist_get_selection_info
2816 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2819 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2820 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2821 src_item = folderview->summaryview->folder_item;
2823 /* re-check (due to acceptable possibly set for folder moves */
2824 if (!(item && item->folder && item->path && !item->no_select &&
2825 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2828 if (item && src_item) {
2829 switch (drag_context->action) {
2830 case GDK_ACTION_COPY:
2831 summary_copy_selected_to(folderview->summaryview, item);
2832 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2834 case GDK_ACTION_MOVE:
2835 case GDK_ACTION_DEFAULT:
2837 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2838 summary_copy_selected_to(folderview->summaryview, item);
2840 summary_move_selected_to(folderview->summaryview, item);
2841 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2844 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2846 /* comes from folderview */
2848 gboolean folder_is_normal = TRUE;
2850 source = data->data + 17;
2851 if (gtk_clist_get_selection_info
2852 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2854 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2857 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2858 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2859 src_item = folder_find_item_from_identifier(source);
2863 src_item->stype == F_NORMAL &&
2864 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2865 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2866 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2867 !folder_has_parent_of_type(src_item, F_TRASH);
2868 if (!item || item->no_select || !src_item
2869 || !folder_is_normal) {
2870 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2874 folderview_move_folder(folderview, src_item, item);
2875 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2877 folderview->nodes_to_recollapse = NULL;
2878 } else if (info == TARGET_MAIL_URI_LIST) {
2879 if (gtk_clist_get_selection_info
2880 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2883 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2885 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2888 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2890 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2893 folderview_finish_dnd(data->data, drag_context, time, item);
2897 static void folderview_drag_end_cb(GtkWidget *widget,
2898 GdkDragContext *drag_context,
2899 FolderView *folderview)
2901 drag_state_stop(folderview);
2902 g_slist_free(folderview->nodes_to_recollapse);
2903 folderview->nodes_to_recollapse = NULL;
2906 void folderview_register_popup(FolderViewPopup *fpopup)
2910 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2911 FolderView *folderview = folderviews->data;
2912 GtkItemFactory *factory;
2914 factory = create_ifactory(folderview, fpopup);
2915 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2917 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2920 void folderview_unregister_popup(FolderViewPopup *fpopup)
2924 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2925 FolderView *folderview = folderviews->data;
2927 g_hash_table_remove(folderview->popups, fpopup->klass);
2929 g_hash_table_remove(folderview_popups, fpopup->klass);