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 gboolean last_open = prefs_common.always_show_msg;
806 prefs_common.select_on_entry = SELECTONENTRY_MNU;
807 prefs_common.always_show_msg = TRUE;
809 if ((node = folderview_find_next_marked(ctree, folderview->opened))
811 folderview_select_node(folderview, node);
815 if (!folderview->opened ||
816 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
819 /* search again from the first node */
820 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
821 folderview_select_node(folderview, node);
824 prefs_common.select_on_entry = last_sel;
825 prefs_common.always_show_msg = last_open;
828 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
834 node = gtkut_ctree_node_next(ctree, node);
836 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
838 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
839 item = gtk_ctree_node_get_row_data(ctree, node);
840 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
847 void folderview_select_next_unread(FolderView *folderview)
849 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
850 GtkCTreeNode *node = NULL;
851 SelectOnEntry last_sel = prefs_common.select_on_entry;
852 gboolean last_open = prefs_common.always_show_msg;
854 prefs_common.select_on_entry = SELECTONENTRY_UNM;
855 prefs_common.always_show_msg = TRUE;
857 if ((node = folderview_find_next_unread(ctree, folderview->opened))
859 folderview_select_node(folderview, node);
863 if (!folderview->opened ||
864 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
867 /* search again from the first node */
868 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
869 folderview_select_node(folderview, node);
872 prefs_common.select_on_entry = last_sel;
873 prefs_common.always_show_msg = last_open;
876 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
882 node = gtkut_ctree_node_next(ctree, node);
884 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
886 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
887 item = gtk_ctree_node_get_row_data(ctree, node);
888 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
895 void folderview_select_next_new(FolderView *folderview)
897 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
898 GtkCTreeNode *node = NULL;
899 SelectOnEntry last_sel = prefs_common.select_on_entry;
900 gboolean last_open = prefs_common.always_show_msg;
902 prefs_common.select_on_entry = SELECTONENTRY_NUM;
903 prefs_common.always_show_msg = TRUE;
905 if ((node = folderview_find_next_new(ctree, folderview->opened))
907 folderview_select_node(folderview, node);
911 if (!folderview->opened ||
912 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
915 /* search again from the first node */
916 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
917 folderview_select_node(folderview, node);
920 prefs_common.select_on_entry = last_sel;
921 prefs_common.always_show_msg = last_open;
924 FolderItem *folderview_get_selected_item(FolderView *folderview)
926 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
928 if (!folderview->selected) return NULL;
929 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
932 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
934 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
935 static GtkCTreeNode *prev_row = NULL;
937 gint new, unread, total;
938 gchar *new_str, *unread_str, *total_str;
939 gint *col_pos = folderview->col_pos;
943 item = gtk_ctree_node_get_row_data(ctree, row);
946 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
947 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
948 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
950 unread = atoi(unread_str);
951 total = atoi(total_str);
955 folderview_update_node(folderview, row);
958 void folderview_append_item(FolderItem *item)
962 g_return_if_fail(item != NULL);
963 g_return_if_fail(item->folder != NULL);
964 if (folder_item_parent(item)) return;
966 for (list = folderview_list; list != NULL; list = list->next) {
967 FolderView *folderview = (FolderView *)list->data;
968 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
969 GtkCTreeNode *node, *child;
970 gint *col_pos = folderview->col_pos;
972 node = gtk_ctree_find_by_row_data(ctree, NULL,
973 folder_item_parent(item));
975 child = gtk_ctree_find_by_row_data(ctree, node, item);
977 gchar *text[N_FOLDER_COLS] =
978 {NULL, "0", "0", "0"};
980 gtk_clist_freeze(GTK_CLIST(ctree));
982 text[col_pos[F_COL_FOLDER]] = item->name;
983 child = gtk_sctree_insert_node
984 (ctree, node, NULL, text,
986 folderxpm, folderxpmmask,
987 folderopenxpm, folderopenxpmmask,
989 gtk_ctree_node_set_row_data(ctree, child, item);
990 gtk_ctree_expand(ctree, node);
991 folderview_update_node(folderview, child);
992 folderview_sort_folders(folderview, node,
995 gtk_clist_thaw(GTK_CLIST(ctree));
1001 static void folderview_set_folders(FolderView *folderview)
1004 #ifndef HAVE_LIBETPAN
1005 static gboolean missing_imap_warning = TRUE;
1007 list = folder_get_list();
1009 for (; list != NULL; list = list->next) {
1010 #ifndef HAVE_LIBETPAN
1011 if ((FOLDER(list->data))
1012 && (FOLDER(list->data))->klass
1013 && (FOLDER(list->data))->klass->type == F_IMAP
1014 && missing_imap_warning) {
1015 missing_imap_warning = FALSE;
1017 _("You have one or more IMAP accounts "
1018 "defined. However this version of "
1019 "Sylpheed-Claws has been built without "
1020 "IMAP support; your IMAP account(s) are "
1022 "You probably need to "
1023 "install libetpan and recompile "
1024 "Sylpheed-Claws."));
1027 folderview_append_folder(folderview, FOLDER(list->data));
1031 static gchar *get_scan_str(FolderItem *item)
1034 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1035 item->folder->name, G_DIR_SEPARATOR,
1038 return g_strdup_printf(_("Scanning folder %s ..."),
1039 item->folder->name);
1041 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1045 for (list = folderview_list; list != NULL; list = list->next) {
1046 FolderView *folderview = (FolderView *)list->data;
1047 MainWindow *mainwin = folderview->mainwin;
1048 gchar *str = get_scan_str(item);
1050 STATUSBAR_PUSH(mainwin, str);
1051 STATUSBAR_POP(mainwin);
1056 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1060 g_return_if_fail(folder != NULL);
1062 if (!folder->klass->scan_tree) return;
1065 alertpanel_full(_("Rebuild folder tree"),
1066 _("Rebuilding the folder tree will remove "
1067 "local caches. Do you want to continue?"),
1068 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1069 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1070 != G_ALERTALTERNATE) {
1076 window = label_window_create(_("Rebuilding folder tree..."));
1078 window = label_window_create(_("Scanning folder tree..."));
1080 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1081 folder_scan_tree(folder, rebuild);
1082 folder_set_ui_func(folder, NULL, NULL);
1084 folderview_set_all();
1086 gtk_widget_destroy(window);
1090 /** folderview_check_new()
1091 * Scan and update the folder and return the
1092 * count the number of new messages since last check.
1093 * \param folder the folder to check for new messages
1094 * \return the number of new messages since last check
1096 gint folderview_check_new(Folder *folder)
1100 FolderView *folderview;
1104 gint former_new_msgs = 0;
1105 gint former_new = 0, former_unread = 0, former_total;
1107 for (list = folderview_list; list != NULL; list = list->next) {
1108 folderview = (FolderView *)list->data;
1109 ctree = GTK_CTREE(folderview->ctree);
1112 main_window_lock(folderview->mainwin);
1114 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1115 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1117 item = gtk_ctree_node_get_row_data(ctree, node);
1118 if (!item || !item->path || !item->folder) continue;
1119 if (item->no_select) continue;
1120 if (folder && folder != item->folder) continue;
1121 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1122 if (!item->prefs->newmailcheck) continue;
1123 if (item->processing_pending == TRUE) {
1124 debug_print("skipping %s, processing pending\n",
1125 item->path ? item->path : item->name);
1129 str = get_scan_str(item);
1131 STATUSBAR_PUSH(folderview->mainwin, str);
1135 folderview_scan_tree_func(item->folder, item, NULL);
1136 former_new = item->new_msgs;
1137 former_unread = item->unread_msgs;
1138 former_total = item->total_msgs;
1140 if (item->folder->klass->scan_required &&
1141 (item->folder->klass->scan_required(item->folder, item) ||
1142 item->folder->inbox == item ||
1143 item->opened == TRUE ||
1144 item->processing_pending == TRUE)) {
1145 if (folder_item_scan(item) < 0) {
1146 summaryview_unlock(folderview->summaryview, item);
1147 if (folder && !FOLDER_IS_LOCAL(folder)) {
1148 STATUSBAR_POP(folderview->mainwin);
1152 } else if (!item->folder->klass->scan_required) {
1153 if (folder_item_scan(item) < 0) {
1154 summaryview_unlock(folderview->summaryview, item);
1155 if (folder && !FOLDER_IS_LOCAL(folder)) {
1156 STATUSBAR_POP(folderview->mainwin);
1161 if (former_new != item->new_msgs ||
1162 former_unread != item->unread_msgs ||
1163 former_total != item->total_msgs)
1164 folderview_update_node(folderview, node);
1166 new_msgs += item->new_msgs;
1167 former_new_msgs += former_new;
1168 STATUSBAR_POP(folderview->mainwin);
1171 main_window_unlock(folderview->mainwin);
1175 folder_write_list();
1176 /* Number of new messages since last check is the just the difference
1177 * between former_new_msgs and new_msgs. If new_msgs is less than
1178 * former_new_msgs, that would mean another session accessed the folder
1179 * and the result is not well defined.
1181 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1185 void folderview_check_new_all(void)
1189 FolderView *folderview;
1191 folderview = (FolderView *)folderview_list->data;
1194 main_window_lock(folderview->mainwin);
1195 window = label_window_create
1196 (_("Checking for new messages in all folders..."));
1198 list = folder_get_list();
1199 for (; list != NULL; list = list->next) {
1200 Folder *folder = list->data;
1202 folderview_check_new(folder);
1205 folder_write_list();
1206 folderview_set_all();
1208 gtk_widget_destroy(window);
1209 main_window_unlock(folderview->mainwin);
1213 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1219 if (!item || !item->folder || !item->folder->node)
1222 node = item->folder->node;
1224 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1225 node = node->children;
1228 (item->new_msgs > 0 ||
1229 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1233 while (node != NULL) {
1234 if (node && node->data) {
1235 FolderItem *next_item = (FolderItem*) node->data;
1237 if (folderview_have_new_children_sub(folderview,
1246 static gboolean folderview_have_new_children(FolderView *folderview,
1249 return folderview_have_new_children_sub(folderview, item, FALSE);
1252 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1258 if (!item || !item->folder || !item->folder->node)
1261 node = item->folder->node;
1263 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1264 node = node->children;
1267 (item->unread_msgs > 0 ||
1268 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1272 while (node != NULL) {
1273 if (node && node->data) {
1274 FolderItem *next_item = (FolderItem*) node->data;
1276 if (folderview_have_unread_children_sub(folderview,
1286 static gboolean folderview_have_unread_children(FolderView *folderview,
1289 return folderview_have_unread_children_sub(folderview, item, FALSE);
1292 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1298 if (!item || !item->folder || !item->folder->node)
1301 node = item->folder->node;
1303 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1304 node = node->children;
1306 if (in_sub && item->search_match){
1310 while (node != NULL) {
1311 if (node && node->data) {
1312 FolderItem *next_item = (FolderItem*) node->data;
1314 if (folderview_have_matching_children_sub(folderview,
1324 static gboolean folderview_have_matching_children(FolderView *folderview,
1327 return folderview_have_matching_children_sub(folderview, item, FALSE);
1330 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1336 if (!item || !item->folder || !item->folder->node)
1339 node = item->folder->node;
1341 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1342 node = node->children;
1344 if (item->marked_msgs != 0) {
1348 while (node != NULL) {
1349 if (node && node->data) {
1350 FolderItem *next_item = (FolderItem*) node->data;
1352 if (folderview_have_marked_children_sub(folderview,
1361 static gboolean folderview_have_marked_children(FolderView *folderview,
1364 return folderview_have_marked_children_sub(folderview, item, FALSE);
1367 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1369 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1370 GtkStyle *style = NULL;
1371 GtkStyle *color_style = NULL;
1373 GdkPixmap *xpm, *openxpm;
1374 GdkBitmap *mask, *openmask;
1375 static GdkPixmap *searchicon;
1376 static GdkBitmap *searchmask;
1377 gboolean mark = FALSE;
1380 gboolean add_unread_mark;
1381 gboolean add_sub_match_mark;
1382 gboolean use_bold, use_color;
1383 gint *col_pos = folderview->col_pos;
1384 SpecialFolderItemType stype;
1386 item = gtk_ctree_node_get_row_data(ctree, node);
1387 g_return_if_fail(item != NULL);
1389 if (!GTK_CTREE_ROW(node)->expanded)
1390 mark = folderview_have_marked_children(folderview, item);
1392 mark = (item->marked_msgs != 0);
1394 stype = item->stype;
1395 if (stype == F_NORMAL) {
1396 if (folder_has_parent_of_type(item, F_TRASH))
1398 else if (folder_has_parent_of_type(item, F_DRAFT))
1400 else if (folder_has_parent_of_type(item, F_OUTBOX))
1402 else if (folder_has_parent_of_type(item, F_QUEUE))
1407 if (item->hide_read_msgs) {
1408 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1409 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1410 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1411 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1413 xpm = mark?m_inboxxpm:inboxxpm;
1414 mask = mark?m_inboxxpmmask:inboxxpmmask;
1415 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1416 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1420 if (item->hide_read_msgs) {
1421 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1422 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1423 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1424 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1426 xpm = mark?m_outboxxpm:outboxxpm;
1427 mask = mark?m_outboxxpmmask:outboxxpmmask;
1428 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1429 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1433 if (item->hide_read_msgs) {
1434 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1435 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1436 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1437 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1439 xpm = mark?m_queuexpm:queuexpm;
1440 mask = mark?m_queuexpmmask:queuexpmmask;
1441 openxpm = mark?m_queueopenxpm:queueopenxpm;
1442 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1446 if (item->hide_read_msgs) {
1447 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1448 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1449 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1450 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1452 xpm = mark?m_trashxpm:trashxpm;
1453 mask = mark?m_trashxpmmask:trashxpmmask;
1454 openxpm = mark?m_trashopenxpm:trashopenxpm;
1455 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1459 xpm = mark?m_draftsxpm:draftsxpm;
1460 mask = mark?m_draftsxpmmask:draftsxpmmask;
1461 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1462 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1465 if (item->hide_read_msgs) {
1466 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1467 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1468 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1469 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1471 xpm = mark?m_folderxpm:folderxpm;
1472 mask = mark?m_folderxpmmask:folderxpmmask;
1473 openxpm = mark?m_folderopenxpm:folderopenxpm;
1474 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1478 if (item->no_select) {
1479 xpm = openxpm = noselectxpm;
1480 mask = openmask = noselectxpmmask;
1483 name = folder_item_get_name(item);
1485 if (!GTK_CTREE_ROW(node)->expanded) {
1486 add_unread_mark = folderview_have_unread_children(
1488 add_sub_match_mark = folderview_have_matching_children(
1491 add_unread_mark = FALSE;
1492 add_sub_match_mark = FALSE;
1495 if (item->search_match) {
1497 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1498 &searchicon, &searchmask);
1500 xpm = openxpm = searchicon;
1501 mask = openmask = searchmask;
1504 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1505 prefs_common.display_folder_unread) {
1506 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1507 add_unread_mark ? "+" : "");
1508 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1509 xpm, mask, openxpm, openmask,
1510 FALSE, GTK_CTREE_ROW(node)->expanded);
1512 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1513 prefs_common.display_folder_unread)
1514 || add_sub_match_mark) {
1516 if (item->unread_msgs > 0)
1517 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1518 add_unread_mark || add_sub_match_mark ? "+" : "",
1519 item->unreadmarked_msgs > 0 ? "!":"");
1521 str = g_strdup_printf("%s (+)", name);
1522 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1523 xpm, mask, openxpm, openmask,
1524 FALSE, GTK_CTREE_ROW(node)->expanded);
1527 str = g_strdup_printf("%s%s", name,
1528 item->unreadmarked_msgs > 0 ? " (!)":"");
1530 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1531 xpm, mask, openxpm, openmask,
1532 FALSE, GTK_CTREE_ROW(node)->expanded);
1537 if (!folder_item_parent(item)) {
1538 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1539 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1540 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1542 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1543 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1544 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1547 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1548 folder_has_parent_of_type(item, F_DRAFT) ||
1549 folder_has_parent_of_type(item, F_TRASH)) {
1550 use_bold = use_color = FALSE;
1551 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1552 /* highlight queue folder if there are any messages */
1553 use_bold = use_color = (item->total_msgs > 0);
1555 /* if unread messages exist, print with bold font */
1556 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1558 /* if new messages exist, print with colored letter */
1560 (item->new_msgs > 0) ||
1562 folderview_have_new_children(folderview, item));
1565 gtk_ctree_node_set_foreground(ctree, node, NULL);
1570 if (item->prefs->color > 0 && !use_color) {
1571 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1572 color_style = gtk_style_copy(bold_style);
1573 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1574 style = color_style;
1575 } else if (use_color) {
1576 style = bold_color_style;
1579 if (item->op_count > 0) {
1580 style = bold_tgtfold_style;
1582 } else if (use_color) {
1583 style = normal_color_style;
1584 gtk_ctree_node_set_foreground(ctree, node,
1585 &folderview->color_new);
1586 } else if (item->op_count > 0) {
1587 style = bold_tgtfold_style;
1588 } else if (item->prefs->color > 0) {
1590 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1591 color_style = gtk_style_copy(normal_style);
1592 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1593 style = color_style;
1595 style = normal_style;
1598 gtk_ctree_node_set_row_style(ctree, node, style);
1600 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1601 folderview_update_node(folderview, node);
1604 #if !CLAWS /* keep it here for syncs */
1605 void folderview_update_item(FolderItem *item, gboolean update_summary)
1608 FolderView *folderview;
1612 g_return_if_fail(item != NULL);
1614 for (list = folderview_list; list != NULL; list = list->next) {
1615 folderview = (FolderView *)list->data;
1616 ctree = GTK_CTREE(folderview->ctree);
1618 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1620 folderview_update_node(folderview, node);
1621 if (update_summary && folderview->opened == node)
1622 summary_show(folderview->summaryview,
1629 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1632 FolderView *folderview;
1636 g_return_if_fail(item != NULL);
1638 for (list = folderview_list; list != NULL; list = list->next) {
1639 folderview = (FolderView *)list->data;
1640 ctree = GTK_CTREE(folderview->ctree);
1642 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1644 item->search_match = matches;
1645 folderview_update_node(folderview, node);
1650 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1652 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1653 FolderView *folderview = (FolderView *)data;
1656 g_return_val_if_fail(update_info != NULL, TRUE);
1657 g_return_val_if_fail(update_info->item != NULL, TRUE);
1658 g_return_val_if_fail(folderview != NULL, FALSE);
1660 ctree = GTK_CTREE(folderview->ctree);
1662 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1664 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1665 folderview_update_node(folderview, node);
1666 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1667 summary_show(folderview->summaryview, update_info->item);
1673 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1676 /* CLAWS: share this joy with other hook functions ... */
1677 folder_item_update((FolderItem *)key,
1678 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1681 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1684 FolderItemUpdateFlags flags;
1686 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1688 for (list = folderview_list; list != NULL; list = list->next)
1689 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1690 GINT_TO_POINTER(flags));
1693 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1694 GNode *gnode, GtkCTreeNode *cnode,
1697 FolderView *folderview = (FolderView *)data;
1698 FolderItem *item = FOLDER_ITEM(gnode->data);
1700 g_return_val_if_fail(item != NULL, FALSE);
1702 gtk_ctree_node_set_row_data(ctree, cnode, item);
1703 folderview_update_node(folderview, cnode);
1708 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1711 FolderView *folderview = (FolderView *)data;
1714 if (GTK_CTREE_ROW(node)->children) {
1715 item = gtk_ctree_node_get_row_data(ctree, node);
1716 g_return_if_fail(item != NULL);
1718 if (!item->collapsed)
1719 gtk_ctree_expand(ctree, node);
1721 folderview_update_node(folderview, node);
1725 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1726 GtkCTreeNode *root, GtkCTreeNode **prev)
1729 GtkCTreeNode *node, *parent, *sibling;
1731 node = gtk_ctree_find_by_row_data(ctree, root, item);
1733 g_warning("%s not found.\n", item->path);
1735 parent = GTK_CTREE_ROW(node)->parent;
1736 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1737 sibling = GTK_CTREE_ROW(*prev)->sibling;
1739 sibling = GTK_CTREE_ROW(parent)->children;
1743 tmp = gtk_ctree_node_get_row_data
1745 if (tmp->stype != F_NORMAL)
1746 sibling = GTK_CTREE_ROW(sibling)->sibling;
1750 if (node != sibling)
1751 gtk_ctree_move(ctree, node, parent, sibling);
1758 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1761 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1762 GtkCTreeNode *prev = NULL;
1764 gtk_sctree_sort_recursive(ctree, root);
1766 if (root && GTK_CTREE_ROW(root)->parent) return;
1768 set_special_folder(ctree, folder->inbox, root, &prev);
1769 set_special_folder(ctree, folder->outbox, root, &prev);
1770 set_special_folder(ctree, folder->draft, root, &prev);
1771 set_special_folder(ctree, folder->queue, root, &prev);
1772 set_special_folder(ctree, folder->trash, root, &prev);
1775 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1777 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1780 g_return_if_fail(folder != NULL);
1782 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1783 folderview_gnode_func, folderview);
1784 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1786 folderview_sort_folders(folderview, root, folder);
1789 /* callback functions */
1791 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1792 FolderView *folderview)
1794 GtkCList *clist = GTK_CLIST(ctree);
1795 gint prev_row = -1, row = -1, column = -1;
1798 FolderViewPopup *fpopup;
1799 GtkItemFactory *fpopup_factory;
1801 FolderItem *special_trash = NULL, *special_queue = NULL;
1804 if (!event) return FALSE;
1806 if (event->button == 1 || event->button == 2) {
1807 folderview->open_folder = TRUE;
1809 if (event->type == GDK_2BUTTON_PRESS) {
1810 if (clist->selection) {
1813 node = GTK_CTREE_NODE(clist->selection->data);
1815 gtk_ctree_toggle_expansion(
1823 if (event->button == 2 || event->button == 3) {
1825 if (clist->selection) {
1828 node = GTK_CTREE_NODE(clist->selection->data);
1830 prev_row = gtkut_ctree_get_nth_from_node
1831 (GTK_CTREE(ctree), node);
1834 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1837 if (prev_row != row) {
1838 gtk_clist_unselect_all(clist);
1839 if (event->button == 2)
1840 folderview_select_node
1842 gtk_ctree_node_nth(GTK_CTREE(ctree),
1845 gtk_clist_select_row(clist, row, column);
1849 if (event->button != 3) return FALSE;
1851 item = gtk_clist_get_row_data(clist, row);
1852 g_return_val_if_fail(item != NULL, FALSE);
1853 g_return_val_if_fail(item->folder != NULL, FALSE);
1854 folder = item->folder;
1856 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1858 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1860 fpopup = g_hash_table_lookup(folderview_popups, "common");
1861 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1864 if (fpopup->set_sensitivity != NULL)
1865 fpopup->set_sensitivity(fpopup_factory, item);
1867 if (NULL != (ac = account_find_from_item(item))) {
1868 special_trash = account_get_special_folder(ac, F_TRASH);
1869 special_queue = account_get_special_folder(ac, F_QUEUE);
1872 if ((item == folder->trash || item == special_trash
1873 || folder_has_parent_of_type(item, F_TRASH)) &&
1874 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1875 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1876 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1877 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1878 && !folder_has_parent_of_type(item, F_TRASH)) {
1879 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1880 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1883 if ((item == folder->queue || item == special_queue
1884 || folder_has_parent_of_type(item, F_QUEUE)) &&
1885 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1886 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1887 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1888 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1889 && !folder_has_parent_of_type(item, F_QUEUE)) {
1890 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1891 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1894 #define SET_SENS(name, sens) \
1895 menu_set_sensitive(fpopup_factory, name, sens)
1897 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1898 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1899 folderview->selected == folderview->opened);
1900 SET_SENS("/Properties...", TRUE);
1901 SET_SENS("/Processing...", item->node->parent != NULL);
1902 if (item == folder->trash || item == special_trash
1903 || folder_has_parent_of_type(item, F_TRASH)) {
1904 GSList *msglist = folder_item_get_msg_list(item);
1905 SET_SENS("/Empty trash...", msglist != NULL);
1906 procmsg_msg_list_free(msglist);
1908 if (item == folder->queue || item == special_queue
1909 || folder_has_parent_of_type(item, F_QUEUE)) {
1910 GSList *msglist = folder_item_get_msg_list(item);
1911 SET_SENS("/Send queue...", msglist != NULL);
1912 procmsg_msg_list_free(msglist);
1916 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1917 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1918 event->button, event->time);
1923 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1924 FolderView *folderview)
1926 if (!event) return FALSE;
1928 if (event->button == 1 && folderview->open_folder == FALSE &&
1929 folderview->opened != NULL) {
1930 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1931 folderview->opened);
1932 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1938 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1939 FolderView *folderview)
1941 if (!event) return FALSE;
1943 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1946 switch (event->keyval) {
1948 if (folderview->selected) {
1949 folderview_select_node(folderview,
1950 folderview->selected);
1954 if (folderview->selected) {
1955 if (folderview->opened == folderview->selected &&
1956 (!folderview->summaryview->folder_item ||
1957 folderview->summaryview->folder_item->total_msgs == 0))
1958 folderview_select_next_unread(folderview);
1960 folderview_select_node(folderview,
1961 folderview->selected);
1971 typedef struct _PostponedSelectData
1976 FolderView *folderview;
1977 } PostponedSelectData;
1979 static gboolean postpone_select(void *data)
1981 PostponedSelectData *psdata = (PostponedSelectData *)data;
1982 debug_print("trying again\n");
1983 psdata->folderview->open_folder = TRUE;
1984 main_window_cursor_normal(psdata->folderview->mainwin);
1985 STATUSBAR_POP(psdata->folderview->mainwin);
1986 folderview_selected(psdata->ctree, psdata->row,
1987 psdata->column, psdata->folderview);
1992 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1993 gint column, FolderView *folderview)
1995 static gboolean can_select = TRUE; /* exclusive lock */
2001 folderview->selected = row;
2003 if (folderview->opened == row) {
2004 folderview->open_folder = FALSE;
2008 if (!can_select || summary_is_locked(folderview->summaryview)) {
2009 if (folderview->opened) {
2010 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2011 gtk_ctree_select(ctree, folderview->opened);
2016 if (!folderview->open_folder) return;
2018 item = gtk_ctree_node_get_row_data(ctree, row);
2019 if (!item || item->no_select) return;
2023 /* Save cache for old folder */
2024 /* We don't want to lose all caches if sylpheed crashed */
2025 if (folderview->opened) {
2026 FolderItem *olditem;
2028 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2030 buf = g_strdup_printf(_("Closing Folder %s..."),
2031 olditem->path ? olditem->path:olditem->name);
2032 /* will be null if we just moved the previously opened folder */
2033 STATUSBAR_PUSH(folderview->mainwin, buf);
2034 main_window_cursor_wait(folderview->mainwin);
2036 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2037 summary_show(folderview->summaryview, NULL);
2038 folder_item_close(olditem);
2039 main_window_cursor_normal(folderview->mainwin);
2040 STATUSBAR_POP(folderview->mainwin);
2044 /* CLAWS: set compose button type: news folder items
2045 * always have a news folder as parent */
2047 toolbar_set_compose_button
2048 (folderview->mainwin->toolbar,
2049 FOLDER_TYPE(item->folder) == F_NEWS ?
2050 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2053 debug_print("Folder %s is selected\n", item->path);
2055 if (!GTK_CTREE_ROW(row)->children)
2056 gtk_ctree_expand(ctree, row);
2057 if (folderview->opened &&
2058 !GTK_CTREE_ROW(folderview->opened)->children)
2059 gtk_ctree_collapse(ctree, folderview->opened);
2061 /* ungrab the mouse event */
2062 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2063 gtk_grab_remove(GTK_WIDGET(ctree));
2064 if (gdk_pointer_is_grabbed())
2065 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2069 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2070 item->path : "(null)");
2071 debug_print("%s\n", buf);
2072 STATUSBAR_PUSH(folderview->mainwin, buf);
2075 main_window_cursor_wait(folderview->mainwin);
2077 res = folder_item_open(item);
2079 main_window_cursor_normal(folderview->mainwin);
2080 STATUSBAR_POP(folderview->mainwin);
2082 alertpanel_error(_("Folder could not be opened."));
2084 folderview->open_folder = FALSE;
2088 } else if (res == -2) {
2089 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2090 data->ctree = ctree;
2092 data->column = column;
2093 data->folderview = folderview;
2094 debug_print("postponing open of %s till end of scan\n",
2095 item->path ? item->path:item->name);
2096 folderview->open_folder = FALSE;
2098 g_timeout_add(500, postpone_select, data);
2102 main_window_cursor_normal(folderview->mainwin);
2105 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2106 opened = summary_show(folderview->summaryview, item);
2108 folder_clean_cache_memory(item);
2111 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2112 gtk_ctree_select(ctree, folderview->opened);
2114 folderview->opened = row;
2115 if (gtk_ctree_node_is_visible(ctree, row)
2116 != GTK_VISIBILITY_FULL)
2117 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2120 STATUSBAR_POP(folderview->mainwin);
2122 folderview->open_folder = FALSE;
2126 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2127 FolderView *folderview)
2131 item = gtk_ctree_node_get_row_data(ctree, node);
2132 g_return_if_fail(item != NULL);
2133 item->collapsed = FALSE;
2134 folderview_update_node(folderview, node);
2137 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2138 FolderView *folderview)
2142 item = gtk_ctree_node_get_row_data(ctree, node);
2143 g_return_if_fail(item != NULL);
2144 item->collapsed = TRUE;
2145 folderview_update_node(folderview, node);
2148 static void folderview_popup_close(GtkMenuShell *menu_shell,
2149 FolderView *folderview)
2151 if (!folderview->opened) return;
2153 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2156 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2157 FolderView *folderview)
2159 FolderColumnType type = folderview->col_state[column].type;
2161 prefs_common.folder_col_size[type] = width;
2164 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2168 folderview_create_folder_node(folderview, item);
2170 if (!item || !item->folder || !item->folder->node)
2173 srcnode = item->folder->node;
2174 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2175 srcnode = srcnode->children;
2176 while (srcnode != NULL) {
2177 if (srcnode && srcnode->data) {
2178 FolderItem *next_item = (FolderItem*) srcnode->data;
2179 folderview_create_folder_node_recursive(folderview, next_item);
2181 srcnode = srcnode->next;
2185 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2187 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2188 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2189 GtkCTreeNode *node, *parent_node;
2190 gint *col_pos = folderview->col_pos;
2191 FolderItemUpdateData hookdata;
2193 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2194 if (parent_node == NULL)
2197 gtk_clist_freeze(GTK_CLIST(ctree));
2199 text[col_pos[F_COL_FOLDER]] = item->name;
2200 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2202 folderxpm, folderxpmmask,
2203 folderopenxpm, folderopenxpmmask,
2205 gtk_ctree_expand(ctree, parent_node);
2206 gtk_ctree_node_set_row_data(ctree, node, item);
2208 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2209 folderview_sort_folders(folderview, parent_node, item->folder);
2211 hookdata.item = item;
2212 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2213 hookdata.msg = NULL;
2214 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2216 gtk_clist_thaw(GTK_CLIST(ctree));
2219 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2222 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2224 GSList *mlist = NULL;
2226 FolderItem *special_trash = NULL;
2229 if (!folderview->selected) return;
2230 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2231 g_return_if_fail(item != NULL);
2232 g_return_if_fail(item->folder != NULL);
2234 if (NULL != (ac = account_find_from_item(item)))
2235 special_trash = account_get_special_folder(ac, F_TRASH);
2237 if (item != item->folder->trash && item != special_trash
2238 && !folder_has_parent_of_type(item, F_TRASH)) return;
2240 if (prefs_common.ask_on_clean) {
2241 if (alertpanel(_("Empty trash"),
2242 _("Delete all messages in trash?"),
2243 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2247 mlist = folder_item_get_msg_list(item);
2249 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2250 MsgInfo * msginfo = (MsgInfo *) cur->data;
2251 if (MSG_IS_LOCKED(msginfo->flags))
2253 /* is it partially received? (partial_recv isn't cached) */
2254 if (msginfo->total_size != 0 &&
2255 msginfo->size != (off_t)msginfo->total_size)
2256 partial_mark_for_delete(msginfo);
2258 procmsg_msg_list_free(mlist);
2260 folder_item_remove_all_msg(item);
2263 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2266 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2268 FolderItem *special_queue = NULL;
2270 gchar *errstr = NULL;
2272 if (!folderview->selected) return;
2273 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2274 g_return_if_fail(item != NULL);
2275 g_return_if_fail(item->folder != NULL);
2277 if (NULL != (ac = account_find_from_item(item)))
2278 special_queue = account_get_special_folder(ac, F_QUEUE);
2280 if (item != item->folder->queue && item != special_queue
2281 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2283 if (procmsg_queue_is_empty(item))
2286 if (prefs_common.work_offline)
2287 if (alertpanel(_("Offline warning"),
2288 _("You're working offline. Override?"),
2289 GTK_STOCK_NO, GTK_STOCK_YES,
2290 NULL) != G_ALERTALTERNATE)
2293 /* ask for confirmation before sending queued messages only
2294 in online mode and if there is at least one message queued
2295 in any of the folder queue
2297 if (prefs_common.confirm_send_queued_messages) {
2298 if (!prefs_common.work_offline) {
2299 if (alertpanel(_("Send queued messages"),
2300 _("Send all queued messages?"),
2301 GTK_STOCK_CANCEL, _("_Send"),
2302 NULL) != G_ALERTALTERNATE)
2307 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2309 alertpanel_error_log(_("Some errors occurred while "
2310 "sending queued messages."));
2312 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2313 "while sending queued messages:\n%s"), errstr);
2315 alertpanel_error_log(tmp);
2321 static void folderview_search_cb(FolderView *folderview, guint action,
2324 summary_search(folderview->summaryview);
2327 static void folderview_property_cb(FolderView *folderview, guint action,
2330 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2333 if (!folderview->selected) return;
2335 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2336 g_return_if_fail(item != NULL);
2337 g_return_if_fail(item->folder != NULL);
2339 prefs_folder_item_open(item);
2342 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2344 GSList *list = NULL;
2345 GSList *done = NULL;
2346 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2348 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2349 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2350 && list->data != node) {
2351 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2352 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2355 for (list = done; list != NULL; list = g_slist_next(list)) {
2356 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2362 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2363 FolderItem *to_folder)
2365 FolderItem *from_parent = NULL;
2366 FolderItem *new_folder = NULL;
2367 GtkCTreeNode *src_node = NULL;
2371 g_return_if_fail(folderview != NULL);
2372 g_return_if_fail(from_folder != NULL);
2373 g_return_if_fail(to_folder != NULL);
2375 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2376 from_parent = folder_item_parent(from_folder);
2378 if (prefs_common.warn_dnd) {
2379 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2380 "sub-folder of '%s' ?"), from_folder->name,
2382 status = alertpanel_full(_("Move folder"), buf,
2383 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2384 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2387 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2389 else if (status & G_ALERTDISABLE)
2390 prefs_common.warn_dnd = FALSE;
2393 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2394 STATUSBAR_PUSH(folderview->mainwin, buf);
2396 summary_clear_all(folderview->summaryview);
2397 folderview->opened = NULL;
2398 folderview->selected = NULL;
2399 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2401 main_window_cursor_wait(folderview->mainwin);
2402 statusbar_verbosity_set(TRUE);
2403 folder_item_update_freeze();
2404 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2405 statusbar_verbosity_set(FALSE);
2406 main_window_cursor_normal(folderview->mainwin);
2407 STATUSBAR_POP(folderview->mainwin);
2408 folder_item_update_thaw();
2409 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2411 folderview_sort_folders(folderview,
2412 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2413 NULL, to_folder), new_folder->folder);
2414 folderview_select(folderview, new_folder);
2416 statusbar_verbosity_set(FALSE);
2417 main_window_cursor_normal(folderview->mainwin);
2418 STATUSBAR_POP(folderview->mainwin);
2419 folder_item_update_thaw();
2421 case F_MOVE_FAILED_DEST_IS_PARENT:
2422 alertpanel_error(_("Source and destination are the same."));
2424 case F_MOVE_FAILED_DEST_IS_CHILD:
2425 alertpanel_error(_("Can't move a folder to one of its children."));
2427 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2428 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2431 alertpanel_error(_("Move failed!"));
2436 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2439 static gint folderview_clist_compare(GtkCList *clist,
2440 gconstpointer ptr1, gconstpointer ptr2)
2442 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2443 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2446 return (item2->name != NULL);
2450 return g_utf8_collate(item1->name, item2->name);
2453 static void folderview_processing_cb(FolderView *folderview, guint action,
2456 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2460 if (!folderview->selected) return;
2462 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2463 g_return_if_fail(item != NULL);
2464 g_return_if_fail(item->folder != NULL);
2466 id = folder_item_get_identifier(item);
2467 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2470 prefs_filtering_open(&item->prefs->processing, title, NULL, NULL);
2474 void folderview_set_target_folder_color(gint color_op)
2478 FolderView *folderview;
2480 for (list = folderview_list; list != NULL; list = list->next) {
2481 folderview = (FolderView *)list->data;
2482 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2484 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2485 folderview->color_op;
2491 static gchar *last_font = NULL;
2492 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2500 void folderview_reflect_prefs(void)
2502 gboolean update_font = TRUE;
2503 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2504 FolderItem *item = folderview_get_selected_item(folderview);
2505 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2506 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2507 gint height = pos->value;
2509 if (last_font && !strcmp(last_font, NORMAL_FONT))
2510 update_font = FALSE;
2513 last_font = g_strdup(NORMAL_FONT);
2516 normal_style = normal_color_style = bold_style =
2517 bold_color_style = bold_tgtfold_style = NULL;
2519 folderview_init(folderview);
2521 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2522 folderview_column_set_titles(folderview);
2523 folderview_set_all();
2525 g_signal_handlers_block_by_func
2526 (G_OBJECT(folderview->ctree),
2527 G_CALLBACK(folderview_selected), folderview);
2530 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2531 GTK_CTREE(folderview->ctree), NULL, item);
2533 folderview_select(folderview, item);
2534 folderview->selected = node;
2537 g_signal_handlers_unblock_by_func
2538 (G_OBJECT(folderview->ctree),
2539 G_CALLBACK(folderview_selected), folderview);
2541 pos = gtk_scrolled_window_get_vadjustment(
2542 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2543 gtk_adjustment_set_value(pos, height);
2544 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2547 static void drag_state_stop(FolderView *folderview)
2549 if (folderview->drag_timer)
2550 gtk_timeout_remove(folderview->drag_timer);
2551 folderview->drag_timer = 0;
2552 folderview->drag_node = NULL;
2555 static gint folderview_defer_expand(FolderView *folderview)
2557 if (folderview->drag_node) {
2558 folderview_recollapse_nodes(folderview, folderview->drag_node);
2559 if (folderview->drag_item->collapsed) {
2560 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2561 folderview->nodes_to_recollapse = g_slist_append
2562 (folderview->nodes_to_recollapse, folderview->drag_node);
2565 folderview->drag_item = NULL;
2566 folderview->drag_timer = 0;
2570 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2572 /* the idea is that we call drag_state_start() whenever we want expansion to
2573 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2574 * we need to call drag_state_stop() */
2575 drag_state_stop(folderview);
2576 /* request expansion */
2577 if (0 != (folderview->drag_timer = gtk_timeout_add
2578 (prefs_common.hover_timeout,
2579 (GtkFunction)folderview_defer_expand,
2581 folderview->drag_node = node;
2582 folderview->drag_item = item;
2586 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2587 FolderView *folderview)
2589 GdkDragContext *context;
2591 g_return_if_fail(folderview != NULL);
2592 if (folderview->selected == NULL) return;
2593 if (folderview->nodes_to_recollapse)
2594 g_slist_free(folderview->nodes_to_recollapse);
2595 folderview->nodes_to_recollapse = NULL;
2596 context = gtk_drag_begin(widget, folderview->target_list,
2597 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2598 gtk_drag_set_icon_default(context);
2601 static void folderview_drag_data_get(GtkWidget *widget,
2602 GdkDragContext *drag_context,
2603 GtkSelectionData *selection_data,
2606 FolderView *folderview)
2610 gchar *source = NULL;
2611 if (info == TARGET_DUMMY) {
2612 for (cur = GTK_CLIST(folderview->ctree)->selection;
2613 cur != NULL; cur = cur->next) {
2614 item = gtk_ctree_node_get_row_data
2615 (GTK_CTREE(folderview->ctree),
2616 GTK_CTREE_NODE(cur->data));
2618 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2619 gtk_selection_data_set(selection_data,
2620 selection_data->target, 8,
2621 source, strlen(source));
2627 g_warning("unknown info %d\n", info);
2631 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2633 FolderUpdateData *hookdata;
2634 FolderView *folderview;
2638 folderview = (FolderView *) userdata;
2639 g_return_val_if_fail(hookdata != NULL, FALSE);
2640 g_return_val_if_fail(folderview != NULL, FALSE);
2642 ctree = folderview->ctree;
2643 g_return_val_if_fail(ctree != NULL, FALSE);
2645 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2646 folderview_create_folder_node(folderview, hookdata->item);
2647 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2648 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2649 NULL, folder_item_parent(hookdata->item));
2650 folderview_sort_folders(folderview, node, hookdata->folder);
2651 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2654 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2656 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2657 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2658 folderview_set(folderview);
2663 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2664 GdkDragContext *context,
2668 FolderView *folderview)
2671 FolderItem *item = NULL, *src_item = NULL;
2672 GtkCTreeNode *node = NULL;
2673 gboolean acceptable = FALSE;
2674 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2675 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2676 int height = (int)pos->page_size;
2677 int total_height = (int)pos->upper;
2678 int vpos = (int) pos->value;
2680 if (gtk_clist_get_selection_info
2681 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2682 GtkWidget *srcwidget;
2684 if (y > height - 24 && height + vpos < total_height)
2685 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2687 if (y < 48 && y > 0)
2688 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2690 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2691 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2692 src_item = folderview->summaryview->folder_item;
2694 srcwidget = gtk_drag_get_source_widget(context);
2695 if (srcwidget == folderview->summaryview->ctree) {
2696 /* comes from summaryview */
2697 /* we are copying messages, so only accept folder items that are not
2698 the source item, are no root items and can copy messages */
2699 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2700 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2702 } else if (srcwidget == folderview->ctree) {
2703 /* comes from folderview */
2704 /* we are moving folder items, only accept folders that are not
2705 the source items and can copy messages and create folder items */
2706 if (item && item->folder && src_item && src_item != item &&
2707 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2708 FOLDER_CLASS(item->folder)->create_folder != NULL)
2711 /* comes from another app */
2712 /* we are adding messages, so only accept folder items that are
2713 no root items and can copy messages */
2714 if (item && item->folder && folder_item_parent(item) != NULL
2715 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2720 if (acceptable || (src_item && src_item == item))
2721 drag_state_start(folderview, node, item);
2724 g_signal_handlers_block_by_func
2726 G_CALLBACK(folderview_selected), folderview);
2727 gtk_ctree_select(GTK_CTREE(widget), node);
2728 g_signal_handlers_unblock_by_func
2730 G_CALLBACK(folderview_selected), folderview);
2731 gdk_drag_status(context,
2732 (context->actions == GDK_ACTION_COPY ?
2733 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2735 if (folderview->opened)
2736 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2737 gdk_drag_status(context, 0, time);
2743 static void folderview_drag_leave_cb(GtkWidget *widget,
2744 GdkDragContext *context,
2746 FolderView *folderview)
2748 drag_state_stop(folderview);
2749 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2752 static void free_info (gpointer stuff, gpointer data)
2757 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2758 guint time, FolderItem *item)
2761 GSList *msglist = NULL;
2762 list = uri_list_extract_filenames(data);
2763 if (!(item && item->folder && folder_item_parent(item) != NULL
2764 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2766 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2770 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2773 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2774 MsgFileInfo *info = NULL;
2776 if (file_is_email((gchar *)tmp->data)) {
2777 info = g_new0(MsgFileInfo, 1);
2778 info->msginfo = NULL;
2779 info->file = (gchar *)tmp->data;
2780 msglist = g_slist_prepend(msglist, info);
2784 msglist = g_slist_reverse(msglist);
2785 folder_item_add_msgs(item, msglist, FALSE);
2786 g_slist_foreach(msglist, free_info, NULL);
2787 g_slist_free(msglist);
2788 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2790 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2792 list_free_strings(list);
2796 static void folderview_drag_received_cb(GtkWidget *widget,
2797 GdkDragContext *drag_context,
2800 GtkSelectionData *data,
2803 FolderView *folderview)
2806 FolderItem *item = NULL, *src_item;
2809 if (info == TARGET_DUMMY) {
2810 drag_state_stop(folderview);
2811 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2812 /* comes from summaryview */
2813 if (gtk_clist_get_selection_info
2814 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2817 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2818 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2819 src_item = folderview->summaryview->folder_item;
2821 /* re-check (due to acceptable possibly set for folder moves */
2822 if (!(item && item->folder && item->path && !item->no_select &&
2823 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2826 if (item && src_item) {
2827 switch (drag_context->action) {
2828 case GDK_ACTION_COPY:
2829 summary_copy_selected_to(folderview->summaryview, item);
2830 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2832 case GDK_ACTION_MOVE:
2833 case GDK_ACTION_DEFAULT:
2835 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2836 summary_copy_selected_to(folderview->summaryview, item);
2838 summary_move_selected_to(folderview->summaryview, item);
2839 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2842 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2844 /* comes from folderview */
2846 gboolean folder_is_normal = TRUE;
2848 source = data->data + 17;
2849 if (gtk_clist_get_selection_info
2850 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2852 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2855 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2856 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2857 src_item = folder_find_item_from_identifier(source);
2861 src_item->stype == F_NORMAL &&
2862 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2863 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2864 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2865 !folder_has_parent_of_type(src_item, F_TRASH);
2866 if (!item || item->no_select || !src_item
2867 || !folder_is_normal) {
2868 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2872 folderview_move_folder(folderview, src_item, item);
2873 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2875 folderview->nodes_to_recollapse = NULL;
2876 } else if (info == TARGET_MAIL_URI_LIST) {
2877 if (gtk_clist_get_selection_info
2878 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2881 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2883 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2886 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2888 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2891 folderview_finish_dnd(data->data, drag_context, time, item);
2895 static void folderview_drag_end_cb(GtkWidget *widget,
2896 GdkDragContext *drag_context,
2897 FolderView *folderview)
2899 drag_state_stop(folderview);
2900 g_slist_free(folderview->nodes_to_recollapse);
2901 folderview->nodes_to_recollapse = NULL;
2904 void folderview_register_popup(FolderViewPopup *fpopup)
2908 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2909 FolderView *folderview = folderviews->data;
2910 GtkItemFactory *factory;
2912 factory = create_ifactory(folderview, fpopup);
2913 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2915 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2918 void folderview_unregister_popup(FolderViewPopup *fpopup)
2922 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2923 FolderView *folderview = folderviews->data;
2925 g_hash_table_remove(folderview->popups, fpopup->klass);
2927 g_hash_table_remove(folderview_popups, fpopup->klass);