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"
68 #include "quicksearch.h"
72 #define COL_FOLDER_WIDTH 150
73 #define COL_NUM_WIDTH 32
75 static GList *folderview_list = NULL;
77 static GtkStyle *normal_style;
78 static GtkStyle *normal_color_style;
79 static GtkStyle *bold_style;
80 static GtkStyle *bold_color_style;
81 static GtkStyle *bold_tgtfold_style;
83 static GdkPixmap *inboxxpm;
84 static GdkBitmap *inboxxpmmask;
85 static GdkPixmap *inboxhrmxpm;
86 static GdkBitmap *inboxhrmxpmmask;
87 static GdkPixmap *inboxopenxpm;
88 static GdkBitmap *inboxopenxpmmask;
89 static GdkPixmap *inboxopenhrmxpm;
90 static GdkBitmap *inboxopenhrmxpmmask;
91 static GdkPixmap *outboxxpm;
92 static GdkBitmap *outboxxpmmask;
93 static GdkPixmap *outboxhrmxpm;
94 static GdkBitmap *outboxhrmxpmmask;
95 static GdkPixmap *outboxopenxpm;
96 static GdkBitmap *outboxopenxpmmask;
97 static GdkPixmap *outboxopenhrmxpm;
98 static GdkBitmap *outboxopenhrmxpmmask;
99 static GdkPixmap *folderxpm;
100 static GdkBitmap *folderxpmmask;
101 static GdkPixmap *folderhrmxpm;
102 static GdkBitmap *folderhrmxpmmask;
103 static GdkPixmap *folderopenxpm;
104 static GdkBitmap *folderopenxpmmask;
105 static GdkPixmap *folderopenhrmxpm;
106 static GdkBitmap *folderopenhrmxpmmask;
107 static GdkPixmap *trashopenxpm;
108 static GdkBitmap *trashopenxpmmask;
109 static GdkPixmap *trashopenhrmxpm;
110 static GdkBitmap *trashopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
115 static GdkPixmap *queuexpm;
116 static GdkBitmap *queuexpmmask;
117 static GdkPixmap *queuehrmxpm;
118 static GdkBitmap *queuehrmxpmmask;
119 static GdkPixmap *queueopenxpm;
120 static GdkBitmap *queueopenxpmmask;
121 static GdkPixmap *queueopenhrmxpm;
122 static GdkBitmap *queueopenhrmxpmmask;
123 static GdkPixmap *draftsxpm;
124 static GdkBitmap *draftsxpmmask;
125 static GdkPixmap *draftsopenxpm;
126 static GdkBitmap *draftsopenxpmmask;
127 static GdkPixmap *noselectxpm;
128 static GdkBitmap *noselectxpmmask;
130 static GdkPixmap *m_inboxxpm;
131 static GdkBitmap *m_inboxxpmmask;
132 static GdkPixmap *m_inboxhrmxpm;
133 static GdkBitmap *m_inboxhrmxpmmask;
134 static GdkPixmap *m_inboxopenxpm;
135 static GdkBitmap *m_inboxopenxpmmask;
136 static GdkPixmap *m_inboxopenhrmxpm;
137 static GdkBitmap *m_inboxopenhrmxpmmask;
138 static GdkPixmap *m_outboxxpm;
139 static GdkBitmap *m_outboxxpmmask;
140 static GdkPixmap *m_outboxhrmxpm;
141 static GdkBitmap *m_outboxhrmxpmmask;
142 static GdkPixmap *m_outboxopenxpm;
143 static GdkBitmap *m_outboxopenxpmmask;
144 static GdkPixmap *m_outboxopenhrmxpm;
145 static GdkBitmap *m_outboxopenhrmxpmmask;
146 static GdkPixmap *m_folderxpm;
147 static GdkBitmap *m_folderxpmmask;
148 static GdkPixmap *m_folderhrmxpm;
149 static GdkBitmap *m_folderhrmxpmmask;
150 static GdkPixmap *m_folderopenxpm;
151 static GdkBitmap *m_folderopenxpmmask;
152 static GdkPixmap *m_folderopenhrmxpm;
153 static GdkBitmap *m_folderopenhrmxpmmask;
154 static GdkPixmap *m_trashopenxpm;
155 static GdkBitmap *m_trashopenxpmmask;
156 static GdkPixmap *m_trashopenhrmxpm;
157 static GdkBitmap *m_trashopenhrmxpmmask;
158 static GdkPixmap *m_trashxpm;
159 static GdkBitmap *m_trashxpmmask;
160 static GdkPixmap *m_trashhrmxpm;
161 static GdkBitmap *m_trashhrmxpmmask;
162 static GdkPixmap *m_queuexpm;
163 static GdkBitmap *m_queuexpmmask;
164 static GdkPixmap *m_queuehrmxpm;
165 static GdkBitmap *m_queuehrmxpmmask;
166 static GdkPixmap *m_queueopenxpm;
167 static GdkBitmap *m_queueopenxpmmask;
168 static GdkPixmap *m_queueopenhrmxpm;
169 static GdkBitmap *m_queueopenhrmxpmmask;
170 static GdkPixmap *m_draftsxpm;
171 static GdkBitmap *m_draftsxpmmask;
172 static GdkPixmap *m_draftsopenxpm;
173 static GdkBitmap *m_draftsopenxpmmask;
175 static GdkPixmap *newxpm;
176 static GdkBitmap *newxpmmask;
177 static GdkPixmap *unreadxpm;
178 static GdkBitmap *unreadxpmmask;
179 static GdkPixmap *readxpm;
180 static GdkBitmap *readxpmmask;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 void folderview_create_folder_node (FolderView *folderview,
277 gboolean folderview_update_folder (gpointer source,
279 gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
284 GHashTable *folderview_popups;
286 static GtkItemFactoryEntry folderview_common_popup_entries[] =
288 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
289 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
290 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
291 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
294 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
295 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
296 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
299 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
300 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
301 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
305 GtkTargetEntry folderview_drag_types[] =
307 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
308 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
311 void folderview_initialize(void)
313 FolderViewPopup *fpopup;
315 GSList *entries = NULL;
317 fpopup = g_new0(FolderViewPopup, 1);
319 n_entries = sizeof(folderview_common_popup_entries) /
320 sizeof(folderview_common_popup_entries[0]);
321 for (i = 0; i < n_entries; i++)
322 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
324 fpopup->klass = "common";
325 fpopup->path = "<CommonFolder>";
326 fpopup->entries = entries;
327 fpopup->set_sensitivity = NULL;
329 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
330 g_hash_table_insert(folderview_popups, "common", fpopup);
333 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
336 GtkItemFactory *factory;
337 FolderViewPopup *fpopup_common;
340 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
341 gtk_item_factory_set_translate_func(factory, menu_translate,
344 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
345 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
347 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
348 if (fpopup_common != fpopup)
349 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
350 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
352 popup = gtk_item_factory_get_widget(factory, fpopup->path);
353 g_signal_connect(G_OBJECT(popup), "selection_done",
354 G_CALLBACK(folderview_popup_close),
360 static void create_ifactories(gpointer key, gpointer value, gpointer data)
362 FolderView *folderview = data;
363 FolderViewPopup *fpopup = value;
364 GtkItemFactory *factory;
366 factory = create_ifactory(folderview, fpopup);
367 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
370 static void folderview_column_set_titles(FolderView *folderview)
372 GtkWidget *ctree = folderview->ctree;
373 GtkWidget *label_new;
374 GtkWidget *label_unread;
375 GtkWidget *label_total;
377 GtkWidget *hbox_unread;
378 GtkWidget *hbox_total;
379 gint *col_pos = folderview->col_pos;
381 debug_print("setting titles...\n");
382 gtk_widget_realize(folderview->ctree);
383 gtk_widget_show_all(folderview->scrolledwin);
385 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
386 * instead text (text overflows making them unreadable and ugly) */
387 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
388 &newxpm, &newxpmmask);
389 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
390 &unreadxpm, &unreadxpmmask);
391 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
392 &readxpm, &readxpmmask);
394 label_new = gtk_pixmap_new(newxpm, newxpmmask);
395 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
396 label_total = gtk_pixmap_new(readxpm, readxpmmask);
398 hbox_new = gtk_hbox_new(FALSE, 4);
399 hbox_unread = gtk_hbox_new(FALSE, 4);
400 hbox_total = gtk_hbox_new(FALSE, 4);
403 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
404 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
405 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
406 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
407 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
408 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
410 gtk_widget_show_all(hbox_new);
411 gtk_widget_show_all(hbox_unread);
412 gtk_widget_show_all(hbox_total);
414 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
415 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
416 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
419 GtkWidget *folderview_ctree_create(FolderView *folderview)
423 FolderColumnState *col_state;
424 FolderColumnType type;
425 gchar *titles[N_FOLDER_COLS];
427 GtkWidget *scrolledwin = folderview->scrolledwin;
429 debug_print("creating tree...\n");
430 memset(titles, 0, sizeof(titles));
432 col_state = prefs_folder_column_get_config();
433 memset(titles, 0, sizeof(titles));
435 col_pos = folderview->col_pos;
437 for (i = 0; i < N_FOLDER_COLS; i++) {
438 folderview->col_state[i] = col_state[i];
439 type = col_state[i].type;
443 titles[col_pos[F_COL_FOLDER]] = _("Folder");
444 titles[col_pos[F_COL_NEW]] = _("New");
445 titles[col_pos[F_COL_UNREAD]] = _("Unread");
446 /* TRANSLATORS: This in Number sign in American style */
447 titles[col_pos[F_COL_TOTAL]] = _("#");
449 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
452 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
453 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
455 gtk_clist_set_column_justification(GTK_CLIST(ctree),
456 col_pos[F_COL_UNREAD],
458 gtk_clist_set_column_justification(GTK_CLIST(ctree),
459 col_pos[F_COL_TOTAL],
461 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
462 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
463 GTK_CTREE_EXPANDER_SQUARE);
464 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
465 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
467 /* don't let title buttons take key focus */
468 for (i = 0; i < N_FOLDER_COLS; i++) {
469 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
471 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
472 prefs_common.folder_col_size[i]);
473 gtk_clist_set_column_visibility
474 (GTK_CLIST(ctree), i, col_state[i].visible);
477 g_signal_connect(G_OBJECT(ctree), "key_press_event",
478 G_CALLBACK(folderview_key_pressed),
480 g_signal_connect(G_OBJECT(ctree), "button_press_event",
481 G_CALLBACK(folderview_button_pressed),
483 g_signal_connect(G_OBJECT(ctree), "button_release_event",
484 G_CALLBACK(folderview_button_released),
486 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
487 G_CALLBACK(folderview_selected), folderview);
488 g_signal_connect(G_OBJECT(ctree), "start_drag",
489 G_CALLBACK(folderview_start_drag), folderview);
490 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
491 G_CALLBACK(folderview_drag_data_get),
494 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
495 G_CALLBACK(folderview_tree_expanded),
497 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
498 G_CALLBACK(folderview_tree_collapsed),
501 g_signal_connect(G_OBJECT(ctree), "resize_column",
502 G_CALLBACK(folderview_col_resized),
506 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
507 folderview_drag_types, 2,
508 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
509 g_signal_connect(G_OBJECT(ctree), "drag_motion",
510 G_CALLBACK(folderview_drag_motion_cb),
512 g_signal_connect(G_OBJECT(ctree), "drag_leave",
513 G_CALLBACK(folderview_drag_leave_cb),
515 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
516 G_CALLBACK(folderview_drag_received_cb),
518 g_signal_connect(G_OBJECT(ctree), "drag_end",
519 G_CALLBACK(folderview_drag_end_cb),
522 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
527 void folderview_set_column_order(FolderView *folderview)
530 FolderItem *item = folderview_get_selected_item(folderview);
531 GtkWidget *scrolledwin = folderview->scrolledwin;
533 debug_print("recreating tree...\n");
534 gtk_widget_destroy(folderview->ctree);
536 folderview->ctree = ctree = folderview_ctree_create(folderview);
537 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
538 GTK_CLIST(ctree)->hadjustment);
539 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
540 GTK_CLIST(ctree)->vadjustment);
541 gtk_widget_show(ctree);
543 folderview_set(folderview);
544 folderview_column_set_titles(folderview);
546 folderview_select(folderview,item);
549 FolderView *folderview_create(void)
551 FolderView *folderview;
552 GtkWidget *scrolledwin;
555 debug_print("Creating folder view...\n");
556 folderview = g_new0(FolderView, 1);
558 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
559 gtk_scrolled_window_set_policy
560 (GTK_SCROLLED_WINDOW(scrolledwin),
561 GTK_POLICY_AUTOMATIC,
562 prefs_common.folderview_vscrollbar_policy);
563 gtk_widget_set_size_request(scrolledwin,
564 prefs_common.folderview_width,
565 prefs_common.folderview_height);
567 folderview->scrolledwin = scrolledwin;
568 ctree = folderview_ctree_create(folderview);
570 /* create popup factories */
571 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
572 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
574 folderview->ctree = ctree;
576 folderview->folder_update_callback_id =
577 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
578 folderview->folder_item_update_callback_id =
579 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
581 gtk_widget_show_all(scrolledwin);
583 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
584 folderview_list = g_list_append(folderview_list, folderview);
589 void folderview_init(FolderView *folderview)
591 GtkWidget *ctree = folderview->ctree;
594 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
595 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
596 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
597 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
598 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
599 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
600 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
601 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
602 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
603 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
604 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
605 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
606 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
607 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
608 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
609 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
610 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
611 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
612 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
613 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
614 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
615 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
616 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
618 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
619 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
620 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
621 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
622 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
623 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
642 PangoFontDescription *font_desc;
643 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
644 font_desc = pango_font_description_from_string(NORMAL_FONT);
646 if (normal_style->font_desc)
647 pango_font_description_free
648 (normal_style->font_desc);
649 normal_style->font_desc = font_desc;
651 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
652 normal_color_style = gtk_style_copy(normal_style);
653 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
655 gtk_widget_set_style(ctree, normal_style);
659 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
660 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
661 pango_font_description_set_weight
662 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
663 bold_color_style = gtk_style_copy(bold_style);
664 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
666 bold_tgtfold_style = gtk_style_copy(bold_style);
667 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
671 void folderview_set(FolderView *folderview)
673 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
674 MainWindow *mainwin = folderview->mainwin;
679 debug_print("Setting folder info...\n");
680 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
682 main_window_cursor_wait(mainwin);
684 folderview->selected = NULL;
685 folderview->opened = NULL;
687 gtk_clist_freeze(GTK_CLIST(ctree));
688 gtk_clist_clear(GTK_CLIST(ctree));
689 gtk_clist_thaw(GTK_CLIST(ctree));
690 gtk_clist_freeze(GTK_CLIST(ctree));
692 folderview_set_folders(folderview);
694 gtk_clist_thaw(GTK_CLIST(ctree));
695 main_window_cursor_normal(mainwin);
696 STATUSBAR_POP(mainwin);
699 void folderview_set_all(void)
703 for (list = folderview_list; list != NULL; list = list->next)
704 folderview_set((FolderView *)list->data);
707 void folderview_select(FolderView *folderview, FolderItem *item)
709 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
711 GtkCTreeNode *old_selected = folderview->selected;
715 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
716 if (node) folderview_select_node(folderview, node);
718 if (old_selected != node)
719 folder_update_op_count();
722 static void mark_all_read_cb(FolderView *folderview, guint action,
728 item = folderview_get_selected_item(folderview);
732 if (folderview->summaryview->folder_item != item
733 && prefs_common.ask_mark_all_read) {
734 val = alertpanel_full(_("Mark all as read"),
735 _("Do you really want to mark all mails in this "
736 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
737 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
739 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
741 else if (val & G_ALERTDISABLE)
742 prefs_common.ask_mark_all_read = FALSE;
745 summary_lock(folderview->summaryview);
746 folder_item_update_freeze();
747 if (folderview->summaryview->folder_item == item)
748 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
749 folderutils_mark_all_read(item);
750 if (folderview->summaryview->folder_item == item)
751 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
752 folder_item_update_thaw();
753 summary_unlock(folderview->summaryview);
756 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
758 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
760 g_return_if_fail(node != NULL);
762 folderview->open_folder = TRUE;
763 gtkut_ctree_set_focus_row(ctree, node);
764 gtk_ctree_select(ctree, node);
765 if (folderview->summaryview->folder_item &&
766 folderview->summaryview->folder_item->total_msgs > 0)
767 gtk_widget_grab_focus(folderview->summaryview->ctree);
769 gtk_widget_grab_focus(folderview->ctree);
771 gtkut_ctree_expand_parent_all(ctree, node);
774 void folderview_unselect(FolderView *folderview)
776 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
778 (GTK_CTREE(folderview->ctree), folderview->opened);
780 folderview->selected = folderview->opened = NULL;
783 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
789 node = gtkut_ctree_node_next(ctree, node);
791 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
793 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
794 item = gtk_ctree_node_get_row_data(ctree, node);
795 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
802 void folderview_select_next_marked(FolderView *folderview)
804 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
805 GtkCTreeNode *node = NULL;
806 SelectOnEntry last_sel = prefs_common.select_on_entry;
807 gboolean last_open = prefs_common.always_show_msg;
809 prefs_common.select_on_entry = SELECTONENTRY_MNU;
810 prefs_common.always_show_msg = TRUE;
812 if ((node = folderview_find_next_marked(ctree, folderview->opened))
814 folderview_select_node(folderview, node);
818 if (!folderview->opened ||
819 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
822 /* search again from the first node */
823 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
824 folderview_select_node(folderview, node);
827 prefs_common.select_on_entry = last_sel;
828 prefs_common.always_show_msg = last_open;
831 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
837 node = gtkut_ctree_node_next(ctree, node);
839 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
841 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
842 item = gtk_ctree_node_get_row_data(ctree, node);
843 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
850 void folderview_select_next_unread(FolderView *folderview)
852 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
853 GtkCTreeNode *node = NULL;
854 SelectOnEntry last_sel = prefs_common.select_on_entry;
855 gboolean last_open = prefs_common.always_show_msg;
857 prefs_common.select_on_entry = SELECTONENTRY_UNM;
858 prefs_common.always_show_msg = TRUE;
860 if ((node = folderview_find_next_unread(ctree, folderview->opened))
862 folderview_select_node(folderview, node);
866 if (!folderview->opened ||
867 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
870 /* search again from the first node */
871 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
872 folderview_select_node(folderview, node);
875 prefs_common.select_on_entry = last_sel;
876 prefs_common.always_show_msg = last_open;
879 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
885 node = gtkut_ctree_node_next(ctree, node);
887 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
889 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
890 item = gtk_ctree_node_get_row_data(ctree, node);
891 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
898 void folderview_select_next_new(FolderView *folderview)
900 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
901 GtkCTreeNode *node = NULL;
902 SelectOnEntry last_sel = prefs_common.select_on_entry;
903 gboolean last_open = prefs_common.always_show_msg;
905 prefs_common.select_on_entry = SELECTONENTRY_NUM;
906 prefs_common.always_show_msg = TRUE;
908 if ((node = folderview_find_next_new(ctree, folderview->opened))
910 folderview_select_node(folderview, node);
914 if (!folderview->opened ||
915 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
918 /* search again from the first node */
919 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
920 folderview_select_node(folderview, node);
923 prefs_common.select_on_entry = last_sel;
924 prefs_common.always_show_msg = last_open;
927 FolderItem *folderview_get_selected_item(FolderView *folderview)
929 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
931 if (!folderview->selected) return NULL;
932 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
935 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
937 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
938 static GtkCTreeNode *prev_row = NULL;
940 gint new, unread, total;
941 gchar *new_str, *unread_str, *total_str;
942 gint *col_pos = folderview->col_pos;
946 item = gtk_ctree_node_get_row_data(ctree, row);
949 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
950 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
951 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
953 unread = atoi(unread_str);
954 total = atoi(total_str);
958 folderview_update_node(folderview, row);
961 void folderview_append_item(FolderItem *item)
965 g_return_if_fail(item != NULL);
966 g_return_if_fail(item->folder != NULL);
967 if (folder_item_parent(item)) return;
969 for (list = folderview_list; list != NULL; list = list->next) {
970 FolderView *folderview = (FolderView *)list->data;
971 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
972 GtkCTreeNode *node, *child;
973 gint *col_pos = folderview->col_pos;
975 node = gtk_ctree_find_by_row_data(ctree, NULL,
976 folder_item_parent(item));
978 child = gtk_ctree_find_by_row_data(ctree, node, item);
980 gchar *text[N_FOLDER_COLS] =
981 {NULL, "0", "0", "0"};
983 gtk_clist_freeze(GTK_CLIST(ctree));
985 text[col_pos[F_COL_FOLDER]] = item->name;
986 child = gtk_sctree_insert_node
987 (ctree, node, NULL, text,
989 folderxpm, folderxpmmask,
990 folderopenxpm, folderopenxpmmask,
992 gtk_ctree_node_set_row_data(ctree, child, item);
993 gtk_ctree_expand(ctree, node);
994 folderview_update_node(folderview, child);
995 folderview_sort_folders(folderview, node,
998 gtk_clist_thaw(GTK_CLIST(ctree));
1004 static void folderview_set_folders(FolderView *folderview)
1007 #ifndef HAVE_LIBETPAN
1008 static gboolean missing_imap_warning = TRUE;
1010 list = folder_get_list();
1012 for (; list != NULL; list = list->next) {
1013 #ifndef HAVE_LIBETPAN
1014 if ((FOLDER(list->data))
1015 && (FOLDER(list->data))->klass
1016 && (FOLDER(list->data))->klass->type == F_IMAP
1017 && missing_imap_warning) {
1018 missing_imap_warning = FALSE;
1020 _("You have one or more IMAP accounts "
1021 "defined. However this version of "
1022 "Sylpheed-Claws has been built without "
1023 "IMAP support; your IMAP account(s) are "
1025 "You probably need to "
1026 "install libetpan and recompile "
1027 "Sylpheed-Claws."));
1030 folderview_append_folder(folderview, FOLDER(list->data));
1034 static gchar *get_scan_str(FolderItem *item)
1037 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1038 item->folder->name, G_DIR_SEPARATOR,
1041 return g_strdup_printf(_("Scanning folder %s ..."),
1042 item->folder->name);
1044 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1048 for (list = folderview_list; list != NULL; list = list->next) {
1049 FolderView *folderview = (FolderView *)list->data;
1050 MainWindow *mainwin = folderview->mainwin;
1051 gchar *str = get_scan_str(item);
1053 STATUSBAR_PUSH(mainwin, str);
1054 STATUSBAR_POP(mainwin);
1059 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1063 g_return_if_fail(folder != NULL);
1065 if (!folder->klass->scan_tree) return;
1068 alertpanel_full(_("Rebuild folder tree"),
1069 _("Rebuilding the folder tree will remove "
1070 "local caches. Do you want to continue?"),
1071 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1072 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1073 != G_ALERTALTERNATE) {
1079 window = label_window_create(_("Rebuilding folder tree..."));
1081 window = label_window_create(_("Scanning folder tree..."));
1083 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1084 folder_scan_tree(folder, rebuild);
1085 folder_set_ui_func(folder, NULL, NULL);
1087 folderview_set_all();
1089 gtk_widget_destroy(window);
1093 /** folderview_check_new()
1094 * Scan and update the folder and return the
1095 * count the number of new messages since last check.
1096 * \param folder the folder to check for new messages
1097 * \return the number of new messages since last check
1099 gint folderview_check_new(Folder *folder)
1103 FolderView *folderview;
1107 gint former_new_msgs = 0;
1108 gint former_new = 0, former_unread = 0, former_total;
1110 for (list = folderview_list; list != NULL; list = list->next) {
1111 folderview = (FolderView *)list->data;
1112 ctree = GTK_CTREE(folderview->ctree);
1115 main_window_lock(folderview->mainwin);
1117 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1118 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1120 item = gtk_ctree_node_get_row_data(ctree, node);
1121 if (!item || !item->path || !item->folder) continue;
1122 if (item->no_select) continue;
1123 if (folder && folder != item->folder) continue;
1124 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1125 if (!item->prefs->newmailcheck) continue;
1126 if (item->processing_pending == TRUE) {
1127 debug_print("skipping %s, processing pending\n",
1128 item->path ? item->path : item->name);
1132 str = get_scan_str(item);
1134 STATUSBAR_PUSH(folderview->mainwin, str);
1138 folderview_scan_tree_func(item->folder, item, NULL);
1139 former_new = item->new_msgs;
1140 former_unread = item->unread_msgs;
1141 former_total = item->total_msgs;
1143 if (item->folder->klass->scan_required &&
1144 (item->folder->klass->scan_required(item->folder, item) ||
1145 item->folder->inbox == item ||
1146 item->opened == TRUE ||
1147 item->processing_pending == TRUE)) {
1148 if (folder_item_scan(item) < 0) {
1149 summaryview_unlock(folderview->summaryview, item);
1150 if (folder && !FOLDER_IS_LOCAL(folder)) {
1151 STATUSBAR_POP(folderview->mainwin);
1155 } else if (!item->folder->klass->scan_required) {
1156 if (folder_item_scan(item) < 0) {
1157 summaryview_unlock(folderview->summaryview, item);
1158 if (folder && !FOLDER_IS_LOCAL(folder)) {
1159 STATUSBAR_POP(folderview->mainwin);
1164 if (former_new != item->new_msgs ||
1165 former_unread != item->unread_msgs ||
1166 former_total != item->total_msgs)
1167 folderview_update_node(folderview, node);
1169 new_msgs += item->new_msgs;
1170 former_new_msgs += former_new;
1171 STATUSBAR_POP(folderview->mainwin);
1174 main_window_unlock(folderview->mainwin);
1178 folder_write_list();
1179 /* Number of new messages since last check is the just the difference
1180 * between former_new_msgs and new_msgs. If new_msgs is less than
1181 * former_new_msgs, that would mean another session accessed the folder
1182 * and the result is not well defined.
1184 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1188 void folderview_check_new_all(void)
1192 FolderView *folderview;
1194 folderview = (FolderView *)folderview_list->data;
1197 main_window_lock(folderview->mainwin);
1198 window = label_window_create
1199 (_("Checking for new messages in all folders..."));
1201 list = folder_get_list();
1202 for (; list != NULL; list = list->next) {
1203 Folder *folder = list->data;
1205 folderview_check_new(folder);
1208 folder_write_list();
1209 folderview_set_all();
1211 gtk_widget_destroy(window);
1212 main_window_unlock(folderview->mainwin);
1216 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1222 if (!item || !item->folder || !item->folder->node)
1225 node = item->folder->node;
1227 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1228 node = node->children;
1231 (item->new_msgs > 0 ||
1232 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1236 while (node != NULL) {
1237 if (node && node->data) {
1238 FolderItem *next_item = (FolderItem*) node->data;
1240 if (folderview_have_new_children_sub(folderview,
1249 static gboolean folderview_have_new_children(FolderView *folderview,
1252 return folderview_have_new_children_sub(folderview, item, FALSE);
1255 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1261 if (!item || !item->folder || !item->folder->node)
1264 node = item->folder->node;
1266 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1267 node = node->children;
1270 (item->unread_msgs > 0 ||
1271 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1275 while (node != NULL) {
1276 if (node && node->data) {
1277 FolderItem *next_item = (FolderItem*) node->data;
1279 if (folderview_have_unread_children_sub(folderview,
1289 static gboolean folderview_have_unread_children(FolderView *folderview,
1292 return folderview_have_unread_children_sub(folderview, item, FALSE);
1295 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1301 if (!item || !item->folder || !item->folder->node)
1304 node = item->folder->node;
1306 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1307 node = node->children;
1309 if (in_sub && item->search_match){
1313 while (node != NULL) {
1314 if (node && node->data) {
1315 FolderItem *next_item = (FolderItem*) node->data;
1317 if (folderview_have_matching_children_sub(folderview,
1327 static gboolean folderview_have_matching_children(FolderView *folderview,
1330 return folderview_have_matching_children_sub(folderview, item, FALSE);
1333 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1339 if (!item || !item->folder || !item->folder->node)
1342 node = item->folder->node;
1344 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1345 node = node->children;
1347 if (item->marked_msgs != 0) {
1351 while (node != NULL) {
1352 if (node && node->data) {
1353 FolderItem *next_item = (FolderItem*) node->data;
1355 if (folderview_have_marked_children_sub(folderview,
1364 static gboolean folderview_have_marked_children(FolderView *folderview,
1367 return folderview_have_marked_children_sub(folderview, item, FALSE);
1370 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1372 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1373 GtkStyle *style = NULL;
1374 GtkStyle *color_style = NULL;
1376 GdkPixmap *xpm, *openxpm;
1377 GdkBitmap *mask, *openmask;
1378 static GdkPixmap *searchicon;
1379 static GdkBitmap *searchmask;
1380 gboolean mark = FALSE;
1383 gboolean add_unread_mark;
1384 gboolean add_sub_match_mark;
1385 gboolean use_bold, use_color;
1386 gint *col_pos = folderview->col_pos;
1387 SpecialFolderItemType stype;
1389 item = gtk_ctree_node_get_row_data(ctree, node);
1390 g_return_if_fail(item != NULL);
1392 if (!GTK_CTREE_ROW(node)->expanded)
1393 mark = folderview_have_marked_children(folderview, item);
1395 mark = (item->marked_msgs != 0);
1397 stype = item->stype;
1398 if (stype == F_NORMAL) {
1399 if (folder_has_parent_of_type(item, F_TRASH))
1401 else if (folder_has_parent_of_type(item, F_DRAFT))
1403 else if (folder_has_parent_of_type(item, F_OUTBOX))
1405 else if (folder_has_parent_of_type(item, F_QUEUE))
1410 if (item->hide_read_msgs) {
1411 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1412 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1413 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1414 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1416 xpm = mark?m_inboxxpm:inboxxpm;
1417 mask = mark?m_inboxxpmmask:inboxxpmmask;
1418 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1419 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1423 if (item->hide_read_msgs) {
1424 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1425 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1426 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1427 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1429 xpm = mark?m_outboxxpm:outboxxpm;
1430 mask = mark?m_outboxxpmmask:outboxxpmmask;
1431 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1432 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1436 if (item->hide_read_msgs) {
1437 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1438 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1439 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1440 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1442 xpm = mark?m_queuexpm:queuexpm;
1443 mask = mark?m_queuexpmmask:queuexpmmask;
1444 openxpm = mark?m_queueopenxpm:queueopenxpm;
1445 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1449 if (item->hide_read_msgs) {
1450 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1451 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1452 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1453 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1455 xpm = mark?m_trashxpm:trashxpm;
1456 mask = mark?m_trashxpmmask:trashxpmmask;
1457 openxpm = mark?m_trashopenxpm:trashopenxpm;
1458 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1462 xpm = mark?m_draftsxpm:draftsxpm;
1463 mask = mark?m_draftsxpmmask:draftsxpmmask;
1464 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1465 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1468 if (item->hide_read_msgs) {
1469 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1470 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1471 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1472 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1474 xpm = mark?m_folderxpm:folderxpm;
1475 mask = mark?m_folderxpmmask:folderxpmmask;
1476 openxpm = mark?m_folderopenxpm:folderopenxpm;
1477 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1481 if (item->no_select) {
1482 xpm = openxpm = noselectxpm;
1483 mask = openmask = noselectxpmmask;
1486 name = folder_item_get_name(item);
1488 if (!GTK_CTREE_ROW(node)->expanded) {
1489 add_unread_mark = folderview_have_unread_children(
1491 add_sub_match_mark = folderview_have_matching_children(
1494 add_unread_mark = FALSE;
1495 add_sub_match_mark = FALSE;
1498 if (item->search_match) {
1500 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1501 &searchicon, &searchmask);
1503 xpm = openxpm = searchicon;
1504 mask = openmask = searchmask;
1507 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1508 prefs_common.display_folder_unread) {
1509 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1510 add_unread_mark ? "+" : "");
1511 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1512 xpm, mask, openxpm, openmask,
1513 FALSE, GTK_CTREE_ROW(node)->expanded);
1515 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1516 prefs_common.display_folder_unread)
1517 || add_sub_match_mark) {
1519 if (item->unread_msgs > 0)
1520 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1521 add_unread_mark || add_sub_match_mark ? "+" : "",
1522 item->unreadmarked_msgs > 0 ? "!":"");
1524 str = g_strdup_printf("%s (+)", name);
1525 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1526 xpm, mask, openxpm, openmask,
1527 FALSE, GTK_CTREE_ROW(node)->expanded);
1530 str = g_strdup_printf("%s%s", name,
1531 item->unreadmarked_msgs > 0 ? " (!)":"");
1533 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1534 xpm, mask, openxpm, openmask,
1535 FALSE, GTK_CTREE_ROW(node)->expanded);
1540 if (!folder_item_parent(item)) {
1541 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1542 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1543 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1545 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1546 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1547 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1550 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1551 folder_has_parent_of_type(item, F_DRAFT) ||
1552 folder_has_parent_of_type(item, F_TRASH)) {
1553 use_bold = use_color = FALSE;
1554 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1555 /* highlight queue folder if there are any messages */
1556 use_bold = use_color = (item->total_msgs > 0);
1558 /* if unread messages exist, print with bold font */
1559 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1561 /* if new messages exist, print with colored letter */
1563 (item->new_msgs > 0) ||
1565 folderview_have_new_children(folderview, item));
1568 gtk_ctree_node_set_foreground(ctree, node, NULL);
1573 if (item->prefs->color > 0 && !use_color) {
1574 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1575 color_style = gtk_style_copy(bold_style);
1576 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1577 style = color_style;
1578 } else if (use_color) {
1579 style = bold_color_style;
1582 if (item->op_count > 0) {
1583 style = bold_tgtfold_style;
1585 } else if (use_color) {
1586 style = normal_color_style;
1587 gtk_ctree_node_set_foreground(ctree, node,
1588 &folderview->color_new);
1589 } else if (item->op_count > 0) {
1590 style = bold_tgtfold_style;
1591 } else if (item->prefs->color > 0) {
1593 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1594 color_style = gtk_style_copy(normal_style);
1595 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1596 style = color_style;
1598 style = normal_style;
1601 gtk_ctree_node_set_row_style(ctree, node, style);
1603 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1604 folderview_update_node(folderview, node);
1607 #if !CLAWS /* keep it here for syncs */
1608 void folderview_update_item(FolderItem *item, gboolean update_summary)
1611 FolderView *folderview;
1615 g_return_if_fail(item != NULL);
1617 for (list = folderview_list; list != NULL; list = list->next) {
1618 folderview = (FolderView *)list->data;
1619 ctree = GTK_CTREE(folderview->ctree);
1621 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1623 folderview_update_node(folderview, node);
1624 if (update_summary && folderview->opened == node)
1625 summary_show(folderview->summaryview,
1632 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1635 FolderView *folderview;
1639 g_return_if_fail(item != NULL);
1641 for (list = folderview_list; list != NULL; list = list->next) {
1642 folderview = (FolderView *)list->data;
1643 ctree = GTK_CTREE(folderview->ctree);
1645 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1647 item->search_match = matches;
1648 folderview_update_node(folderview, node);
1653 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1655 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1656 FolderView *folderview = (FolderView *)data;
1659 g_return_val_if_fail(update_info != NULL, TRUE);
1660 g_return_val_if_fail(update_info->item != NULL, TRUE);
1661 g_return_val_if_fail(folderview != NULL, FALSE);
1663 ctree = GTK_CTREE(folderview->ctree);
1665 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1667 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1668 folderview_update_node(folderview, node);
1669 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1670 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1671 summary_show(folderview->summaryview, update_info->item);
1677 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1680 /* CLAWS: share this joy with other hook functions ... */
1681 folder_item_update((FolderItem *)key,
1682 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1685 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1688 FolderItemUpdateFlags flags;
1690 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1692 for (list = folderview_list; list != NULL; list = list->next)
1693 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1694 GINT_TO_POINTER(flags));
1697 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1698 GNode *gnode, GtkCTreeNode *cnode,
1701 FolderView *folderview = (FolderView *)data;
1702 FolderItem *item = FOLDER_ITEM(gnode->data);
1704 g_return_val_if_fail(item != NULL, FALSE);
1706 gtk_ctree_node_set_row_data(ctree, cnode, item);
1707 folderview_update_node(folderview, cnode);
1712 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1715 FolderView *folderview = (FolderView *)data;
1718 if (GTK_CTREE_ROW(node)->children) {
1719 item = gtk_ctree_node_get_row_data(ctree, node);
1720 g_return_if_fail(item != NULL);
1722 if (!item->collapsed)
1723 gtk_ctree_expand(ctree, node);
1725 folderview_update_node(folderview, node);
1729 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1730 GtkCTreeNode *root, GtkCTreeNode **prev)
1733 GtkCTreeNode *node, *parent, *sibling;
1735 node = gtk_ctree_find_by_row_data(ctree, root, item);
1737 g_warning("%s not found.\n", item->path);
1739 parent = GTK_CTREE_ROW(node)->parent;
1740 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1741 sibling = GTK_CTREE_ROW(*prev)->sibling;
1743 sibling = GTK_CTREE_ROW(parent)->children;
1747 tmp = gtk_ctree_node_get_row_data
1749 if (tmp->stype != F_NORMAL)
1750 sibling = GTK_CTREE_ROW(sibling)->sibling;
1754 if (node != sibling)
1755 gtk_ctree_move(ctree, node, parent, sibling);
1762 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1765 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1766 GtkCTreeNode *prev = NULL;
1768 gtk_sctree_sort_recursive(ctree, root);
1770 if (root && GTK_CTREE_ROW(root)->parent) return;
1772 set_special_folder(ctree, folder->inbox, root, &prev);
1773 set_special_folder(ctree, folder->outbox, root, &prev);
1774 set_special_folder(ctree, folder->draft, root, &prev);
1775 set_special_folder(ctree, folder->queue, root, &prev);
1776 set_special_folder(ctree, folder->trash, root, &prev);
1779 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1781 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1784 g_return_if_fail(folder != NULL);
1786 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1787 folderview_gnode_func, folderview);
1788 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1790 folderview_sort_folders(folderview, root, folder);
1793 /* callback functions */
1795 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1796 FolderView *folderview)
1798 GtkCList *clist = GTK_CLIST(ctree);
1799 gint prev_row = -1, row = -1, column = -1;
1802 FolderViewPopup *fpopup;
1803 GtkItemFactory *fpopup_factory;
1805 FolderItem *special_trash = NULL, *special_queue = NULL;
1808 if (!event) return FALSE;
1810 if (event->button == 1 || event->button == 2) {
1811 folderview->open_folder = TRUE;
1813 if (event->type == GDK_2BUTTON_PRESS) {
1814 if (clist->selection) {
1817 node = GTK_CTREE_NODE(clist->selection->data);
1819 gtk_ctree_toggle_expansion(
1827 if (event->button == 2 || event->button == 3) {
1829 if (clist->selection) {
1832 node = GTK_CTREE_NODE(clist->selection->data);
1834 prev_row = gtkut_ctree_get_nth_from_node
1835 (GTK_CTREE(ctree), node);
1838 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1841 if (prev_row != row) {
1842 gtk_clist_unselect_all(clist);
1843 if (event->button == 2)
1844 folderview_select_node
1846 gtk_ctree_node_nth(GTK_CTREE(ctree),
1849 gtk_clist_select_row(clist, row, column);
1853 if (event->button != 3) return FALSE;
1855 item = gtk_clist_get_row_data(clist, row);
1856 g_return_val_if_fail(item != NULL, FALSE);
1857 g_return_val_if_fail(item->folder != NULL, FALSE);
1858 folder = item->folder;
1860 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1862 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1864 fpopup = g_hash_table_lookup(folderview_popups, "common");
1865 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1868 if (fpopup->set_sensitivity != NULL)
1869 fpopup->set_sensitivity(fpopup_factory, item);
1871 if (NULL != (ac = account_find_from_item(item))) {
1872 special_trash = account_get_special_folder(ac, F_TRASH);
1873 special_queue = account_get_special_folder(ac, F_QUEUE);
1876 if ((item == folder->trash || item == special_trash
1877 || folder_has_parent_of_type(item, F_TRASH)) &&
1878 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1879 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1880 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1881 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1882 && !folder_has_parent_of_type(item, F_TRASH)) {
1883 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1884 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1887 if ((item == folder->queue || item == special_queue
1888 || folder_has_parent_of_type(item, F_QUEUE)) &&
1889 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1890 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1891 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1892 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1893 && !folder_has_parent_of_type(item, F_QUEUE)) {
1894 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1895 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1898 #define SET_SENS(name, sens) \
1899 menu_set_sensitive(fpopup_factory, name, sens)
1901 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1902 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1903 folderview->selected == folderview->opened);
1904 SET_SENS("/Properties...", TRUE);
1905 SET_SENS("/Processing...", item->node->parent != NULL);
1906 if (item == folder->trash || item == special_trash
1907 || folder_has_parent_of_type(item, F_TRASH)) {
1908 GSList *msglist = folder_item_get_msg_list(item);
1909 SET_SENS("/Empty trash...", msglist != NULL);
1910 procmsg_msg_list_free(msglist);
1912 if (item == folder->queue || item == special_queue
1913 || folder_has_parent_of_type(item, F_QUEUE)) {
1914 GSList *msglist = folder_item_get_msg_list(item);
1915 SET_SENS("/Send queue...", msglist != NULL);
1916 procmsg_msg_list_free(msglist);
1920 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1921 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1922 event->button, event->time);
1927 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1928 FolderView *folderview)
1930 if (!event) return FALSE;
1932 if (event->button == 1 && folderview->open_folder == FALSE &&
1933 folderview->opened != NULL) {
1934 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1935 folderview->opened);
1936 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1942 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1943 FolderView *folderview)
1945 if (!event) return FALSE;
1947 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1950 switch (event->keyval) {
1952 if (folderview->selected) {
1953 folderview_select_node(folderview,
1954 folderview->selected);
1958 if (folderview->selected) {
1959 if (folderview->opened == folderview->selected &&
1960 (!folderview->summaryview->folder_item ||
1961 folderview->summaryview->folder_item->total_msgs == 0))
1962 folderview_select_next_unread(folderview);
1964 folderview_select_node(folderview,
1965 folderview->selected);
1975 typedef struct _PostponedSelectData
1980 FolderView *folderview;
1981 } PostponedSelectData;
1983 static gboolean postpone_select(void *data)
1985 PostponedSelectData *psdata = (PostponedSelectData *)data;
1986 debug_print("trying again\n");
1987 psdata->folderview->open_folder = TRUE;
1988 main_window_cursor_normal(psdata->folderview->mainwin);
1989 STATUSBAR_POP(psdata->folderview->mainwin);
1990 folderview_selected(psdata->ctree, psdata->row,
1991 psdata->column, psdata->folderview);
1996 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1997 gint column, FolderView *folderview)
1999 static gboolean can_select = TRUE; /* exclusive lock */
2004 START_TIMING("--- folderview_selected");
2005 folderview->selected = row;
2007 if (folderview->opened == row) {
2008 folderview->open_folder = FALSE;
2013 if (!can_select || summary_is_locked(folderview->summaryview)) {
2014 if (folderview->opened) {
2015 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2016 gtk_ctree_select(ctree, folderview->opened);
2022 if (!folderview->open_folder) {
2026 item = gtk_ctree_node_get_row_data(ctree, row);
2027 if (!item || item->no_select) {
2034 /* Save cache for old folder */
2035 /* We don't want to lose all caches if sylpheed crashed */
2036 if (folderview->opened) {
2037 FolderItem *olditem;
2039 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2041 buf = g_strdup_printf(_("Closing Folder %s..."),
2042 olditem->path ? olditem->path:olditem->name);
2043 /* will be null if we just moved the previously opened folder */
2044 STATUSBAR_PUSH(folderview->mainwin, buf);
2045 main_window_cursor_wait(folderview->mainwin);
2047 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2048 summary_show(folderview->summaryview, NULL);
2049 folder_item_close(olditem);
2050 main_window_cursor_normal(folderview->mainwin);
2051 STATUSBAR_POP(folderview->mainwin);
2055 /* CLAWS: set compose button type: news folder items
2056 * always have a news folder as parent */
2058 toolbar_set_compose_button
2059 (folderview->mainwin->toolbar,
2060 FOLDER_TYPE(item->folder) == F_NEWS ?
2061 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2064 debug_print("Folder %s is selected\n", item->path);
2066 if (!GTK_CTREE_ROW(row)->children)
2067 gtk_ctree_expand(ctree, row);
2068 if (folderview->opened &&
2069 !GTK_CTREE_ROW(folderview->opened)->children)
2070 gtk_ctree_collapse(ctree, folderview->opened);
2072 /* ungrab the mouse event */
2073 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2074 gtk_grab_remove(GTK_WIDGET(ctree));
2075 if (gdk_pointer_is_grabbed())
2076 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2080 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2081 item->path : "(null)");
2082 debug_print("%s\n", buf);
2083 STATUSBAR_PUSH(folderview->mainwin, buf);
2086 main_window_cursor_wait(folderview->mainwin);
2088 res = folder_item_open(item);
2090 main_window_cursor_normal(folderview->mainwin);
2091 STATUSBAR_POP(folderview->mainwin);
2093 alertpanel_error(_("Folder could not be opened."));
2095 folderview->open_folder = FALSE;
2099 } else if (res == -2) {
2100 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2101 data->ctree = ctree;
2103 data->column = column;
2104 data->folderview = folderview;
2105 debug_print("postponing open of %s till end of scan\n",
2106 item->path ? item->path:item->name);
2107 folderview->open_folder = FALSE;
2109 g_timeout_add(500, postpone_select, data);
2114 main_window_cursor_normal(folderview->mainwin);
2117 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2118 opened = summary_show(folderview->summaryview, item);
2120 folder_clean_cache_memory(item);
2123 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2124 gtk_ctree_select(ctree, folderview->opened);
2126 folderview->opened = row;
2127 if (gtk_ctree_node_is_visible(ctree, row)
2128 != GTK_VISIBILITY_FULL)
2129 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2132 STATUSBAR_POP(folderview->mainwin);
2134 folderview->open_folder = FALSE;
2139 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2140 FolderView *folderview)
2144 item = gtk_ctree_node_get_row_data(ctree, node);
2145 g_return_if_fail(item != NULL);
2146 item->collapsed = FALSE;
2147 folderview_update_node(folderview, node);
2150 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2151 FolderView *folderview)
2155 item = gtk_ctree_node_get_row_data(ctree, node);
2156 g_return_if_fail(item != NULL);
2157 item->collapsed = TRUE;
2158 folderview_update_node(folderview, node);
2161 static void folderview_popup_close(GtkMenuShell *menu_shell,
2162 FolderView *folderview)
2164 if (!folderview->opened) return;
2166 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2169 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2170 FolderView *folderview)
2172 FolderColumnType type = folderview->col_state[column].type;
2174 prefs_common.folder_col_size[type] = width;
2177 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2181 folderview_create_folder_node(folderview, item);
2183 if (!item || !item->folder || !item->folder->node)
2186 srcnode = item->folder->node;
2187 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2188 srcnode = srcnode->children;
2189 while (srcnode != NULL) {
2190 if (srcnode && srcnode->data) {
2191 FolderItem *next_item = (FolderItem*) srcnode->data;
2192 folderview_create_folder_node_recursive(folderview, next_item);
2194 srcnode = srcnode->next;
2198 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2200 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2201 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2202 GtkCTreeNode *node, *parent_node;
2203 gint *col_pos = folderview->col_pos;
2204 FolderItemUpdateData hookdata;
2206 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2207 if (parent_node == NULL)
2210 gtk_clist_freeze(GTK_CLIST(ctree));
2212 text[col_pos[F_COL_FOLDER]] = item->name;
2213 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2215 folderxpm, folderxpmmask,
2216 folderopenxpm, folderopenxpmmask,
2218 gtk_ctree_expand(ctree, parent_node);
2219 gtk_ctree_node_set_row_data(ctree, node, item);
2221 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2222 folderview_sort_folders(folderview, parent_node, item->folder);
2224 hookdata.item = item;
2225 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2226 hookdata.msg = NULL;
2227 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2229 gtk_clist_thaw(GTK_CLIST(ctree));
2232 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2235 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2237 GSList *mlist = NULL;
2239 FolderItem *special_trash = NULL;
2242 if (!folderview->selected) return;
2243 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2244 g_return_if_fail(item != NULL);
2245 g_return_if_fail(item->folder != NULL);
2247 if (NULL != (ac = account_find_from_item(item)))
2248 special_trash = account_get_special_folder(ac, F_TRASH);
2250 if (item != item->folder->trash && item != special_trash
2251 && !folder_has_parent_of_type(item, F_TRASH)) return;
2253 if (prefs_common.ask_on_clean) {
2254 if (alertpanel(_("Empty trash"),
2255 _("Delete all messages in trash?"),
2256 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2260 mlist = folder_item_get_msg_list(item);
2262 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2263 MsgInfo * msginfo = (MsgInfo *) cur->data;
2264 if (MSG_IS_LOCKED(msginfo->flags))
2266 /* is it partially received? (partial_recv isn't cached) */
2267 if (msginfo->total_size != 0 &&
2268 msginfo->size != (off_t)msginfo->total_size)
2269 partial_mark_for_delete(msginfo);
2271 procmsg_msg_list_free(mlist);
2273 folder_item_remove_all_msg(item);
2276 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2279 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2281 FolderItem *special_queue = NULL;
2283 gchar *errstr = NULL;
2285 if (!folderview->selected) return;
2286 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2287 g_return_if_fail(item != NULL);
2288 g_return_if_fail(item->folder != NULL);
2290 if (NULL != (ac = account_find_from_item(item)))
2291 special_queue = account_get_special_folder(ac, F_QUEUE);
2293 if (item != item->folder->queue && item != special_queue
2294 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2296 if (procmsg_queue_is_empty(item))
2299 if (prefs_common.work_offline)
2300 if (alertpanel(_("Offline warning"),
2301 _("You're working offline. Override?"),
2302 GTK_STOCK_NO, GTK_STOCK_YES,
2303 NULL) != G_ALERTALTERNATE)
2306 /* ask for confirmation before sending queued messages only
2307 in online mode and if there is at least one message queued
2308 in any of the folder queue
2310 if (prefs_common.confirm_send_queued_messages) {
2311 if (!prefs_common.work_offline) {
2312 if (alertpanel(_("Send queued messages"),
2313 _("Send all queued messages?"),
2314 GTK_STOCK_CANCEL, _("_Send"),
2315 NULL) != G_ALERTALTERNATE)
2320 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2322 alertpanel_error_log(_("Some errors occurred while "
2323 "sending queued messages."));
2325 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2326 "while sending queued messages:\n%s"), errstr);
2328 alertpanel_error_log(tmp);
2334 static void folderview_search_cb(FolderView *folderview, guint action,
2337 summary_search(folderview->summaryview);
2340 static void folderview_property_cb(FolderView *folderview, guint action,
2343 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2346 if (!folderview->selected) return;
2348 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2349 g_return_if_fail(item != NULL);
2350 g_return_if_fail(item->folder != NULL);
2352 prefs_folder_item_open(item);
2355 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2357 GSList *list = NULL;
2358 GSList *done = NULL;
2359 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2361 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2362 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2363 && list->data != node) {
2364 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2365 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2368 for (list = done; list != NULL; list = g_slist_next(list)) {
2369 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2375 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2376 FolderItem *to_folder)
2378 FolderItem *from_parent = NULL;
2379 FolderItem *new_folder = NULL;
2380 GtkCTreeNode *src_node = NULL;
2384 g_return_if_fail(folderview != NULL);
2385 g_return_if_fail(from_folder != NULL);
2386 g_return_if_fail(to_folder != NULL);
2388 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2389 from_parent = folder_item_parent(from_folder);
2391 if (prefs_common.warn_dnd) {
2392 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2393 "sub-folder of '%s' ?"), from_folder->name,
2395 status = alertpanel_full(_("Move folder"), buf,
2396 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2397 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2400 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2402 else if (status & G_ALERTDISABLE)
2403 prefs_common.warn_dnd = FALSE;
2406 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2407 STATUSBAR_PUSH(folderview->mainwin, buf);
2409 summary_clear_all(folderview->summaryview);
2410 folderview->opened = NULL;
2411 folderview->selected = NULL;
2412 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2414 main_window_cursor_wait(folderview->mainwin);
2415 statusbar_verbosity_set(TRUE);
2416 folder_item_update_freeze();
2417 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2418 statusbar_verbosity_set(FALSE);
2419 main_window_cursor_normal(folderview->mainwin);
2420 STATUSBAR_POP(folderview->mainwin);
2421 folder_item_update_thaw();
2422 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2424 folderview_sort_folders(folderview,
2425 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2426 NULL, to_folder), new_folder->folder);
2427 folderview_select(folderview, new_folder);
2429 statusbar_verbosity_set(FALSE);
2430 main_window_cursor_normal(folderview->mainwin);
2431 STATUSBAR_POP(folderview->mainwin);
2432 folder_item_update_thaw();
2434 case F_MOVE_FAILED_DEST_IS_PARENT:
2435 alertpanel_error(_("Source and destination are the same."));
2437 case F_MOVE_FAILED_DEST_IS_CHILD:
2438 alertpanel_error(_("Can't move a folder to one of its children."));
2440 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2441 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2444 alertpanel_error(_("Move failed!"));
2449 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2452 static gint folderview_clist_compare(GtkCList *clist,
2453 gconstpointer ptr1, gconstpointer ptr2)
2455 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2456 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2459 return (item2->name != NULL);
2463 return g_utf8_collate(item1->name, item2->name);
2466 static void folderview_processing_cb(FolderView *folderview, guint action,
2469 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2473 if (!folderview->selected) return;
2475 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2476 g_return_if_fail(item != NULL);
2477 g_return_if_fail(item->folder != NULL);
2479 id = folder_item_get_identifier(item);
2480 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2483 prefs_filtering_open(&item->prefs->processing, title,
2484 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2488 void folderview_set_target_folder_color(gint color_op)
2492 FolderView *folderview;
2494 for (list = folderview_list; list != NULL; list = list->next) {
2495 folderview = (FolderView *)list->data;
2496 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2498 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2499 folderview->color_op;
2505 static gchar *last_font = NULL;
2506 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2514 void folderview_reflect_prefs(void)
2516 gboolean update_font = TRUE;
2517 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2518 FolderItem *item = folderview_get_selected_item(folderview);
2519 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2520 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2521 gint height = pos->value;
2523 if (last_font && !strcmp(last_font, NORMAL_FONT))
2524 update_font = FALSE;
2527 last_font = g_strdup(NORMAL_FONT);
2530 normal_style = normal_color_style = bold_style =
2531 bold_color_style = bold_tgtfold_style = NULL;
2533 folderview_init(folderview);
2535 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2536 folderview_column_set_titles(folderview);
2537 folderview_set_all();
2539 g_signal_handlers_block_by_func
2540 (G_OBJECT(folderview->ctree),
2541 G_CALLBACK(folderview_selected), folderview);
2544 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2545 GTK_CTREE(folderview->ctree), NULL, item);
2547 folderview_select(folderview, item);
2548 folderview->selected = node;
2551 g_signal_handlers_unblock_by_func
2552 (G_OBJECT(folderview->ctree),
2553 G_CALLBACK(folderview_selected), folderview);
2555 pos = gtk_scrolled_window_get_vadjustment(
2556 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2557 gtk_adjustment_set_value(pos, height);
2558 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2561 static void drag_state_stop(FolderView *folderview)
2563 if (folderview->drag_timer)
2564 gtk_timeout_remove(folderview->drag_timer);
2565 folderview->drag_timer = 0;
2566 folderview->drag_node = NULL;
2569 static gint folderview_defer_expand(FolderView *folderview)
2571 if (folderview->drag_node) {
2572 folderview_recollapse_nodes(folderview, folderview->drag_node);
2573 if (folderview->drag_item->collapsed) {
2574 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2575 folderview->nodes_to_recollapse = g_slist_append
2576 (folderview->nodes_to_recollapse, folderview->drag_node);
2579 folderview->drag_item = NULL;
2580 folderview->drag_timer = 0;
2584 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2586 /* the idea is that we call drag_state_start() whenever we want expansion to
2587 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2588 * we need to call drag_state_stop() */
2589 drag_state_stop(folderview);
2590 /* request expansion */
2591 if (0 != (folderview->drag_timer = gtk_timeout_add
2592 (prefs_common.hover_timeout,
2593 (GtkFunction)folderview_defer_expand,
2595 folderview->drag_node = node;
2596 folderview->drag_item = item;
2600 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2601 FolderView *folderview)
2603 GdkDragContext *context;
2605 g_return_if_fail(folderview != NULL);
2606 if (folderview->selected == NULL) return;
2607 if (folderview->nodes_to_recollapse)
2608 g_slist_free(folderview->nodes_to_recollapse);
2609 folderview->nodes_to_recollapse = NULL;
2610 context = gtk_drag_begin(widget, folderview->target_list,
2611 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2612 gtk_drag_set_icon_default(context);
2615 static void folderview_drag_data_get(GtkWidget *widget,
2616 GdkDragContext *drag_context,
2617 GtkSelectionData *selection_data,
2620 FolderView *folderview)
2624 gchar *source = NULL;
2625 if (info == TARGET_DUMMY) {
2626 for (cur = GTK_CLIST(folderview->ctree)->selection;
2627 cur != NULL; cur = cur->next) {
2628 item = gtk_ctree_node_get_row_data
2629 (GTK_CTREE(folderview->ctree),
2630 GTK_CTREE_NODE(cur->data));
2632 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2633 gtk_selection_data_set(selection_data,
2634 selection_data->target, 8,
2635 source, strlen(source));
2641 g_warning("unknown info %d\n", info);
2645 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2647 FolderUpdateData *hookdata;
2648 FolderView *folderview;
2652 folderview = (FolderView *) userdata;
2653 g_return_val_if_fail(hookdata != NULL, FALSE);
2654 g_return_val_if_fail(folderview != NULL, FALSE);
2656 ctree = folderview->ctree;
2657 g_return_val_if_fail(ctree != NULL, FALSE);
2659 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2660 folderview_create_folder_node(folderview, hookdata->item);
2661 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2662 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2663 NULL, folder_item_parent(hookdata->item));
2664 folderview_sort_folders(folderview, node, hookdata->folder);
2665 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2668 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2670 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2671 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2672 folderview_set(folderview);
2677 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2678 GdkDragContext *context,
2682 FolderView *folderview)
2685 FolderItem *item = NULL, *src_item = NULL;
2686 GtkCTreeNode *node = NULL;
2687 gboolean acceptable = FALSE;
2688 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2689 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2690 int height = (int)pos->page_size;
2691 int total_height = (int)pos->upper;
2692 int vpos = (int) pos->value;
2694 if (gtk_clist_get_selection_info
2695 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2696 GtkWidget *srcwidget;
2698 if (y > height - 24 && height + vpos < total_height)
2699 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2701 if (y < 48 && y > 0)
2702 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2704 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2705 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2706 src_item = folderview->summaryview->folder_item;
2708 srcwidget = gtk_drag_get_source_widget(context);
2709 if (srcwidget == folderview->summaryview->ctree) {
2710 /* comes from summaryview */
2711 /* we are copying messages, so only accept folder items that are not
2712 the source item, are no root items and can copy messages */
2713 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2714 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2716 } else if (srcwidget == folderview->ctree) {
2717 /* comes from folderview */
2718 /* we are moving folder items, only accept folders that are not
2719 the source items and can copy messages and create folder items */
2720 if (item && item->folder && src_item && src_item != item &&
2721 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2722 FOLDER_CLASS(item->folder)->create_folder != NULL)
2725 /* comes from another app */
2726 /* we are adding messages, so only accept folder items that are
2727 no root items and can copy messages */
2728 if (item && item->folder && folder_item_parent(item) != NULL
2729 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2734 if (acceptable || (src_item && src_item == item))
2735 drag_state_start(folderview, node, item);
2738 g_signal_handlers_block_by_func
2740 G_CALLBACK(folderview_selected), folderview);
2741 gtk_ctree_select(GTK_CTREE(widget), node);
2742 g_signal_handlers_unblock_by_func
2744 G_CALLBACK(folderview_selected), folderview);
2745 gdk_drag_status(context,
2746 (context->actions == GDK_ACTION_COPY ?
2747 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2749 if (folderview->opened)
2750 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2751 gdk_drag_status(context, 0, time);
2757 static void folderview_drag_leave_cb(GtkWidget *widget,
2758 GdkDragContext *context,
2760 FolderView *folderview)
2762 drag_state_stop(folderview);
2763 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2766 static void free_info (gpointer stuff, gpointer data)
2771 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2772 guint time, FolderItem *item)
2775 GSList *msglist = NULL;
2776 list = uri_list_extract_filenames(data);
2777 if (!(item && item->folder && folder_item_parent(item) != NULL
2778 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2780 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2784 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2787 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2788 MsgFileInfo *info = NULL;
2790 if (file_is_email((gchar *)tmp->data)) {
2791 info = g_new0(MsgFileInfo, 1);
2792 info->msginfo = NULL;
2793 info->file = (gchar *)tmp->data;
2794 msglist = g_slist_prepend(msglist, info);
2798 msglist = g_slist_reverse(msglist);
2799 folder_item_add_msgs(item, msglist, FALSE);
2800 g_slist_foreach(msglist, free_info, NULL);
2801 g_slist_free(msglist);
2802 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2804 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2806 list_free_strings(list);
2810 static void folderview_drag_received_cb(GtkWidget *widget,
2811 GdkDragContext *drag_context,
2814 GtkSelectionData *data,
2817 FolderView *folderview)
2820 FolderItem *item = NULL, *src_item;
2823 if (info == TARGET_DUMMY) {
2824 drag_state_stop(folderview);
2825 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2826 /* comes from summaryview */
2827 if (gtk_clist_get_selection_info
2828 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2831 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2832 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2833 src_item = folderview->summaryview->folder_item;
2835 /* re-check (due to acceptable possibly set for folder moves */
2836 if (!(item && item->folder && item->path && !item->no_select &&
2837 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2840 if (item && src_item) {
2841 switch (drag_context->action) {
2842 case GDK_ACTION_COPY:
2843 summary_copy_selected_to(folderview->summaryview, item);
2844 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2846 case GDK_ACTION_MOVE:
2847 case GDK_ACTION_DEFAULT:
2849 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2850 summary_copy_selected_to(folderview->summaryview, item);
2852 summary_move_selected_to(folderview->summaryview, item);
2853 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2856 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2858 /* comes from folderview */
2860 gboolean folder_is_normal = TRUE;
2862 source = data->data + 17;
2863 if (gtk_clist_get_selection_info
2864 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2866 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2869 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2870 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2871 src_item = folder_find_item_from_identifier(source);
2875 src_item->stype == F_NORMAL &&
2876 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2877 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2878 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2879 !folder_has_parent_of_type(src_item, F_TRASH);
2880 if (!item || item->no_select || !src_item
2881 || !folder_is_normal) {
2882 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2886 folderview_move_folder(folderview, src_item, item);
2887 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2889 folderview->nodes_to_recollapse = NULL;
2890 } else if (info == TARGET_MAIL_URI_LIST) {
2891 if (gtk_clist_get_selection_info
2892 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2895 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2897 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2900 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2902 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2905 folderview_finish_dnd(data->data, drag_context, time, item);
2909 static void folderview_drag_end_cb(GtkWidget *widget,
2910 GdkDragContext *drag_context,
2911 FolderView *folderview)
2913 drag_state_stop(folderview);
2914 g_slist_free(folderview->nodes_to_recollapse);
2915 folderview->nodes_to_recollapse = NULL;
2918 void folderview_register_popup(FolderViewPopup *fpopup)
2922 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2923 FolderView *folderview = folderviews->data;
2924 GtkItemFactory *factory;
2926 factory = create_ifactory(folderview, fpopup);
2927 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2929 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2932 void folderview_unregister_popup(FolderViewPopup *fpopup)
2936 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2937 FolderView *folderview = folderviews->data;
2939 g_hash_table_remove(folderview->popups, fpopup->klass);
2941 g_hash_table_remove(folderview_popups, fpopup->klass);