2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail 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"
73 #define COL_FOLDER_WIDTH 150
74 #define COL_NUM_WIDTH 32
76 static GList *folderview_list = NULL;
78 static GtkStyle *normal_style;
79 static GtkStyle *normal_color_style;
80 static GtkStyle *bold_style;
81 static GtkStyle *bold_color_style;
82 static GtkStyle *bold_tgtfold_style;
84 static GdkPixmap *inboxxpm;
85 static GdkBitmap *inboxxpmmask;
86 static GdkPixmap *inboxhrmxpm;
87 static GdkBitmap *inboxhrmxpmmask;
88 static GdkPixmap *inboxopenxpm;
89 static GdkBitmap *inboxopenxpmmask;
90 static GdkPixmap *inboxopenhrmxpm;
91 static GdkBitmap *inboxopenhrmxpmmask;
92 static GdkPixmap *outboxxpm;
93 static GdkBitmap *outboxxpmmask;
94 static GdkPixmap *outboxhrmxpm;
95 static GdkBitmap *outboxhrmxpmmask;
96 static GdkPixmap *outboxopenxpm;
97 static GdkBitmap *outboxopenxpmmask;
98 static GdkPixmap *outboxopenhrmxpm;
99 static GdkBitmap *outboxopenhrmxpmmask;
100 static GdkPixmap *folderxpm;
101 static GdkBitmap *folderxpmmask;
102 static GdkPixmap *folderhrmxpm;
103 static GdkBitmap *folderhrmxpmmask;
104 static GdkPixmap *folderopenxpm;
105 static GdkBitmap *folderopenxpmmask;
106 static GdkPixmap *folderopenhrmxpm;
107 static GdkBitmap *folderopenhrmxpmmask;
108 static GdkPixmap *trashopenxpm;
109 static GdkBitmap *trashopenxpmmask;
110 static GdkPixmap *trashopenhrmxpm;
111 static GdkBitmap *trashopenhrmxpmmask;
112 static GdkPixmap *trashxpm;
113 static GdkBitmap *trashxpmmask;
114 static GdkPixmap *trashhrmxpm;
115 static GdkBitmap *trashhrmxpmmask;
116 static GdkPixmap *queuexpm;
117 static GdkBitmap *queuexpmmask;
118 static GdkPixmap *queuehrmxpm;
119 static GdkBitmap *queuehrmxpmmask;
120 static GdkPixmap *queueopenxpm;
121 static GdkBitmap *queueopenxpmmask;
122 static GdkPixmap *queueopenhrmxpm;
123 static GdkBitmap *queueopenhrmxpmmask;
124 static GdkPixmap *draftsxpm;
125 static GdkBitmap *draftsxpmmask;
126 static GdkPixmap *draftsopenxpm;
127 static GdkBitmap *draftsopenxpmmask;
128 static GdkPixmap *noselectxpm;
129 static GdkBitmap *noselectxpmmask;
131 static GdkPixmap *m_inboxxpm;
132 static GdkBitmap *m_inboxxpmmask;
133 static GdkPixmap *m_inboxhrmxpm;
134 static GdkBitmap *m_inboxhrmxpmmask;
135 static GdkPixmap *m_inboxopenxpm;
136 static GdkBitmap *m_inboxopenxpmmask;
137 static GdkPixmap *m_inboxopenhrmxpm;
138 static GdkBitmap *m_inboxopenhrmxpmmask;
139 static GdkPixmap *m_outboxxpm;
140 static GdkBitmap *m_outboxxpmmask;
141 static GdkPixmap *m_outboxhrmxpm;
142 static GdkBitmap *m_outboxhrmxpmmask;
143 static GdkPixmap *m_outboxopenxpm;
144 static GdkBitmap *m_outboxopenxpmmask;
145 static GdkPixmap *m_outboxopenhrmxpm;
146 static GdkBitmap *m_outboxopenhrmxpmmask;
147 static GdkPixmap *m_folderxpm;
148 static GdkBitmap *m_folderxpmmask;
149 static GdkPixmap *m_folderhrmxpm;
150 static GdkBitmap *m_folderhrmxpmmask;
151 static GdkPixmap *m_folderopenxpm;
152 static GdkBitmap *m_folderopenxpmmask;
153 static GdkPixmap *m_folderopenhrmxpm;
154 static GdkBitmap *m_folderopenhrmxpmmask;
155 static GdkPixmap *m_trashopenxpm;
156 static GdkBitmap *m_trashopenxpmmask;
157 static GdkPixmap *m_trashopenhrmxpm;
158 static GdkBitmap *m_trashopenhrmxpmmask;
159 static GdkPixmap *m_trashxpm;
160 static GdkBitmap *m_trashxpmmask;
161 static GdkPixmap *m_trashhrmxpm;
162 static GdkBitmap *m_trashhrmxpmmask;
163 static GdkPixmap *m_queuexpm;
164 static GdkBitmap *m_queuexpmmask;
165 static GdkPixmap *m_queuehrmxpm;
166 static GdkBitmap *m_queuehrmxpmmask;
167 static GdkPixmap *m_queueopenxpm;
168 static GdkBitmap *m_queueopenxpmmask;
169 static GdkPixmap *m_queueopenhrmxpm;
170 static GdkBitmap *m_queueopenhrmxpmmask;
171 static GdkPixmap *m_draftsxpm;
172 static GdkBitmap *m_draftsxpmmask;
173 static GdkPixmap *m_draftsopenxpm;
174 static GdkBitmap *m_draftsopenxpmmask;
176 static GdkPixmap *newxpm;
177 static GdkBitmap *newxpmmask;
178 static GdkPixmap *unreadxpm;
179 static GdkBitmap *unreadxpmmask;
180 static GdkPixmap *readxpm;
181 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 static void folderview_create_folder_node (FolderView *folderview,
277 static gboolean folderview_update_folder (gpointer source,
279 static gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {"/---", NULL, NULL, 0, "<Separator>"},
292 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
293 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
294 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
297 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
298 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
299 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
302 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
303 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
304 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
308 GtkTargetEntry folderview_drag_types[] =
310 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
311 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
314 void folderview_initialize(void)
316 FolderViewPopup *fpopup;
318 GSList *entries = NULL;
320 fpopup = g_new0(FolderViewPopup, 1);
322 n_entries = sizeof(folderview_common_popup_entries) /
323 sizeof(folderview_common_popup_entries[0]);
324 for (i = 0; i < n_entries; i++)
325 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
327 fpopup->klass = "common";
328 fpopup->path = "<CommonFolder>";
329 fpopup->entries = entries;
330 fpopup->set_sensitivity = NULL;
332 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
333 g_hash_table_insert(folderview_popups, "common", fpopup);
336 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
339 GtkItemFactory *factory;
340 FolderViewPopup *fpopup_common;
343 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
344 gtk_item_factory_set_translate_func(factory, menu_translate,
347 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
348 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
350 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
351 if (fpopup_common != fpopup)
352 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
353 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
355 popup = gtk_item_factory_get_widget(factory, fpopup->path);
356 g_signal_connect(G_OBJECT(popup), "selection_done",
357 G_CALLBACK(folderview_popup_close),
363 static void create_ifactories(gpointer key, gpointer value, gpointer data)
365 FolderView *folderview = data;
366 FolderViewPopup *fpopup = value;
367 GtkItemFactory *factory;
369 factory = create_ifactory(folderview, fpopup);
370 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
373 static void folderview_column_set_titles(FolderView *folderview)
375 GtkWidget *ctree = folderview->ctree;
376 GtkWidget *label_new;
377 GtkWidget *label_unread;
378 GtkWidget *label_total;
380 GtkWidget *hbox_unread;
381 GtkWidget *hbox_total;
382 gint *col_pos = folderview->col_pos;
384 debug_print("setting titles...\n");
385 gtk_widget_realize(folderview->ctree);
386 gtk_widget_show_all(folderview->scrolledwin);
388 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
389 * instead text (text overflows making them unreadable and ugly) */
390 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
391 &newxpm, &newxpmmask);
392 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
393 &unreadxpm, &unreadxpmmask);
394 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
395 &readxpm, &readxpmmask);
397 label_new = gtk_image_new_from_pixmap(newxpm, newxpmmask);
398 label_unread = gtk_image_new_from_pixmap(unreadxpm, unreadxpmmask);
399 label_total = gtk_image_new_from_pixmap(readxpm, readxpmmask);
401 gtk_clist_column_titles_active(GTK_CLIST(ctree));
403 hbox_new = gtk_hbox_new(FALSE, 4);
404 hbox_unread = gtk_hbox_new(FALSE, 4);
405 hbox_total = gtk_hbox_new(FALSE, 4);
408 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
409 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
410 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
411 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
412 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
413 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
415 gtk_widget_show_all(hbox_new);
416 gtk_widget_show_all(hbox_unread);
417 gtk_widget_show_all(hbox_total);
419 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
420 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
421 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
423 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
424 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
425 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
428 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
430 FolderView *folderview = (FolderView *)data;
431 GdkEventButton event;
432 if (folderview_get_selected_item(folderview) == NULL)
436 event.time = gtk_get_current_event_time();
438 folderview_set_sens_and_popup_menu(folderview, -1,
445 static GtkWidget *folderview_ctree_create(FolderView *folderview)
449 FolderColumnState *col_state;
450 FolderColumnType type;
451 gchar *titles[N_FOLDER_COLS];
453 GtkWidget *scrolledwin = folderview->scrolledwin;
455 debug_print("creating tree...\n");
456 memset(titles, 0, sizeof(titles));
458 col_state = prefs_folder_column_get_config();
459 memset(titles, 0, sizeof(titles));
461 col_pos = folderview->col_pos;
463 for (i = 0; i < N_FOLDER_COLS; i++) {
464 folderview->col_state[i] = col_state[i];
465 type = col_state[i].type;
469 titles[col_pos[F_COL_FOLDER]] = _("Folder");
470 titles[col_pos[F_COL_NEW]] = _("New");
471 titles[col_pos[F_COL_UNREAD]] = _("Unread");
472 /* TRANSLATORS: This in Number sign in American style */
473 titles[col_pos[F_COL_TOTAL]] = _("#");
475 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
478 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
479 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
481 gtk_clist_set_column_justification(GTK_CLIST(ctree),
482 col_pos[F_COL_UNREAD],
484 gtk_clist_set_column_justification(GTK_CLIST(ctree),
485 col_pos[F_COL_TOTAL],
487 if (prefs_common.enable_dotted_lines) {
488 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
489 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
490 GTK_CTREE_EXPANDER_SQUARE);
492 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
493 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
494 GTK_CTREE_EXPANDER_TRIANGLE);
497 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
498 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
500 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
501 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
503 /* don't let title buttons take key focus */
504 for (i = 0; i < N_FOLDER_COLS; i++) {
505 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
507 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
508 prefs_common.folder_col_size[i]);
509 gtk_clist_set_column_visibility
510 (GTK_CLIST(ctree), i, col_state[i].visible);
513 g_signal_connect(G_OBJECT(ctree), "key_press_event",
514 G_CALLBACK(folderview_key_pressed),
516 g_signal_connect(G_OBJECT(ctree), "button_press_event",
517 G_CALLBACK(folderview_button_pressed),
519 g_signal_connect(G_OBJECT(ctree), "popup-menu",
520 G_CALLBACK(folderview_popup_menu), folderview);
521 g_signal_connect(G_OBJECT(ctree), "button_release_event",
522 G_CALLBACK(folderview_button_released),
524 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
525 G_CALLBACK(folderview_selected), folderview);
526 g_signal_connect(G_OBJECT(ctree), "start_drag",
527 G_CALLBACK(folderview_start_drag), folderview);
528 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
529 G_CALLBACK(folderview_drag_data_get),
532 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
533 G_CALLBACK(folderview_tree_expanded),
535 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
536 G_CALLBACK(folderview_tree_collapsed),
539 g_signal_connect(G_OBJECT(ctree), "resize_column",
540 G_CALLBACK(folderview_col_resized),
544 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
545 folderview_drag_types, 2,
546 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
547 g_signal_connect(G_OBJECT(ctree), "drag_motion",
548 G_CALLBACK(folderview_drag_motion_cb),
550 g_signal_connect(G_OBJECT(ctree), "drag_leave",
551 G_CALLBACK(folderview_drag_leave_cb),
553 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
554 G_CALLBACK(folderview_drag_received_cb),
556 g_signal_connect(G_OBJECT(ctree), "drag_end",
557 G_CALLBACK(folderview_drag_end_cb),
560 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
565 void folderview_set_column_order(FolderView *folderview)
568 FolderItem *item = folderview_get_selected_item(folderview);
569 GtkWidget *scrolledwin = folderview->scrolledwin;
571 debug_print("recreating tree...\n");
572 gtk_widget_destroy(folderview->ctree);
574 folderview->ctree = ctree = folderview_ctree_create(folderview);
575 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
576 GTK_CLIST(ctree)->hadjustment);
577 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
578 GTK_CLIST(ctree)->vadjustment);
579 gtk_widget_show(ctree);
581 folderview_set(folderview);
582 folderview_column_set_titles(folderview);
584 folderview_select(folderview,item);
587 FolderView *folderview_create(void)
589 FolderView *folderview;
590 GtkWidget *scrolledwin;
593 debug_print("Creating folder view...\n");
594 folderview = g_new0(FolderView, 1);
596 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
597 gtk_scrolled_window_set_policy
598 (GTK_SCROLLED_WINDOW(scrolledwin),
599 GTK_POLICY_AUTOMATIC,
600 prefs_common.folderview_vscrollbar_policy);
601 gtk_widget_set_size_request(scrolledwin,
602 prefs_common.folderview_width,
603 prefs_common.folderview_height);
605 folderview->scrolledwin = scrolledwin;
606 ctree = folderview_ctree_create(folderview);
608 /* create popup factories */
609 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
610 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
612 folderview->ctree = ctree;
614 folderview->folder_update_callback_id =
615 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
616 folderview->folder_item_update_callback_id =
617 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
619 gtk_widget_show_all(scrolledwin);
621 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
622 folderview_list = g_list_append(folderview_list, folderview);
627 void folderview_init(FolderView *folderview)
629 GtkWidget *ctree = folderview->ctree;
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
671 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
677 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
680 PangoFontDescription *font_desc;
681 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
682 font_desc = pango_font_description_from_string(NORMAL_FONT);
684 if (normal_style->font_desc)
685 pango_font_description_free
686 (normal_style->font_desc);
687 normal_style->font_desc = font_desc;
689 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
690 normal_color_style = gtk_style_copy(normal_style);
691 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
693 gtk_widget_set_style(ctree, normal_style);
697 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
698 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
699 pango_font_description_set_weight
700 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
701 bold_color_style = gtk_style_copy(bold_style);
702 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
704 bold_tgtfold_style = gtk_style_copy(bold_style);
705 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
709 void folderview_set(FolderView *folderview)
711 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
712 MainWindow *mainwin = folderview->mainwin;
717 debug_print("Setting folder info...\n");
718 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
720 main_window_cursor_wait(mainwin);
722 folderview->selected = NULL;
723 folderview->opened = NULL;
725 gtk_clist_freeze(GTK_CLIST(ctree));
726 gtk_clist_clear(GTK_CLIST(ctree));
727 gtk_clist_thaw(GTK_CLIST(ctree));
728 gtk_clist_freeze(GTK_CLIST(ctree));
730 folderview_set_folders(folderview);
732 gtk_clist_thaw(GTK_CLIST(ctree));
733 main_window_cursor_normal(mainwin);
734 STATUSBAR_POP(mainwin);
737 void folderview_set_all(void)
741 for (list = folderview_list; list != NULL; list = list->next)
742 folderview_set((FolderView *)list->data);
745 void folderview_select(FolderView *folderview, FolderItem *item)
747 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
749 GtkCTreeNode *old_selected = folderview->selected;
753 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
754 if (node) folderview_select_node(folderview, node);
756 if (old_selected != node)
757 folder_update_op_count();
760 static void mark_all_read_cb(FolderView *folderview, guint action,
766 item = folderview_get_selected_item(folderview);
770 if (folderview->summaryview->folder_item != item
771 && prefs_common.ask_mark_all_read) {
772 val = alertpanel_full(_("Mark all as read"),
773 _("Do you really want to mark all mails in this "
774 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
775 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
777 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
779 else if (val & G_ALERTDISABLE)
780 prefs_common.ask_mark_all_read = FALSE;
783 summary_lock(folderview->summaryview);
784 folder_item_update_freeze();
785 if (folderview->summaryview->folder_item == item)
786 summary_freeze(folderview->summaryview);
787 folderutils_mark_all_read(item);
788 if (folderview->summaryview->folder_item == item)
789 summary_thaw(folderview->summaryview);
790 folder_item_update_thaw();
791 summary_unlock(folderview->summaryview);
794 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
796 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
798 g_return_if_fail(node != NULL);
800 if (folderview->open_folder) {
804 folderview->open_folder = TRUE;
805 gtkut_ctree_set_focus_row(ctree, node);
806 gtk_ctree_select(ctree, node);
807 if (folderview->summaryview->folder_item &&
808 folderview->summaryview->folder_item->total_msgs > 0)
809 summary_grab_focus(folderview->summaryview);
811 gtk_widget_grab_focus(folderview->ctree);
813 gtkut_ctree_expand_parent_all(ctree, node);
816 void folderview_unselect(FolderView *folderview)
818 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
820 (GTK_CTREE(folderview->ctree), folderview->opened);
822 folderview->selected = folderview->opened = NULL;
825 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
831 node = gtkut_ctree_node_next(ctree, node);
833 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
835 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
836 item = gtk_ctree_node_get_row_data(ctree, node);
837 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
844 void folderview_select_next_marked(FolderView *folderview)
846 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
847 GtkCTreeNode *node = NULL;
848 SelectOnEntry last_sel = prefs_common.select_on_entry;
849 gboolean last_open = prefs_common.always_show_msg;
851 prefs_common.select_on_entry = SELECTONENTRY_MNU;
852 prefs_common.always_show_msg = TRUE;
854 if ((node = folderview_find_next_marked(ctree, folderview->opened))
856 folderview_select_node(folderview, node);
860 if (!folderview->opened ||
861 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
864 /* search again from the first node */
865 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
866 folderview_select_node(folderview, node);
869 prefs_common.select_on_entry = last_sel;
870 prefs_common.always_show_msg = last_open;
873 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
879 node = gtkut_ctree_node_next(ctree, node);
881 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
883 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
884 item = gtk_ctree_node_get_row_data(ctree, node);
885 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
892 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
894 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
895 GtkCTreeNode *node = NULL;
896 SelectOnEntry last_sel = prefs_common.select_on_entry;
897 gboolean last_open = prefs_common.always_show_msg;
899 prefs_common.select_on_entry = SELECTONENTRY_UNM;
900 prefs_common.always_show_msg = force_open ? TRUE : last_open;
902 if ((node = folderview_find_next_unread(ctree, folderview->opened))
904 folderview_select_node(folderview, node);
908 if (!folderview->opened ||
909 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
912 /* search again from the first node */
913 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
914 folderview_select_node(folderview, node);
917 prefs_common.select_on_entry = last_sel;
918 prefs_common.always_show_msg = last_open;
921 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
927 node = gtkut_ctree_node_next(ctree, node);
929 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
931 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
932 item = gtk_ctree_node_get_row_data(ctree, node);
933 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
940 void folderview_select_next_new(FolderView *folderview)
942 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
943 GtkCTreeNode *node = NULL;
944 SelectOnEntry last_sel = prefs_common.select_on_entry;
945 gboolean last_open = prefs_common.always_show_msg;
947 prefs_common.select_on_entry = SELECTONENTRY_NUM;
948 prefs_common.always_show_msg = TRUE;
950 if ((node = folderview_find_next_new(ctree, folderview->opened))
952 folderview_select_node(folderview, node);
956 if (!folderview->opened ||
957 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
960 /* search again from the first node */
961 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
962 folderview_select_node(folderview, node);
965 prefs_common.select_on_entry = last_sel;
966 prefs_common.always_show_msg = last_open;
969 FolderItem *folderview_get_selected_item(FolderView *folderview)
971 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
973 if (!folderview->selected) return NULL;
974 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
977 static void folderview_set_folders(FolderView *folderview)
980 list = folder_get_list();
982 for (; list != NULL; list = list->next) {
983 folderview_append_folder(folderview, FOLDER(list->data));
987 static gchar *get_scan_str(FolderItem *item)
990 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
991 item->folder->name, G_DIR_SEPARATOR,
994 return g_strdup_printf(_("Scanning folder %s ..."),
997 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1001 for (list = folderview_list; list != NULL; list = list->next) {
1002 FolderView *folderview = (FolderView *)list->data;
1003 MainWindow *mainwin = folderview->mainwin;
1004 gchar *str = get_scan_str(item);
1006 STATUSBAR_PUSH(mainwin, str);
1007 STATUSBAR_POP(mainwin);
1012 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1015 MainWindow *mainwin = mainwindow_get_mainwindow();
1016 FolderView *folderview = NULL;
1017 GtkAdjustment *pos = NULL;
1020 g_return_if_fail(folder != NULL);
1022 if (!folder->klass->scan_tree) return;
1025 alertpanel_full(_("Rebuild folder tree"),
1026 _("Rebuilding the folder tree will remove "
1027 "local caches. Do you want to continue?"),
1028 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1029 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1030 != G_ALERTALTERNATE) {
1036 window = label_window_create(_("Rebuilding folder tree..."));
1038 window = label_window_create(_("Scanning folder tree..."));
1041 folderview = mainwin->folderview;
1044 pos = gtk_scrolled_window_get_vadjustment(
1045 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1046 height = pos->value;
1049 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1050 folder_scan_tree(folder, rebuild);
1051 folder_set_ui_func(folder, NULL, NULL);
1053 folderview_set_all();
1056 pos = gtk_scrolled_window_get_vadjustment(
1057 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1058 gtk_adjustment_set_value(pos, height);
1060 gtk_widget_destroy(window);
1064 void folderview_fast_rescan_tree(Folder *folder)
1067 MainWindow *mainwin = mainwindow_get_mainwindow();
1068 FolderView *folderview = NULL;
1069 GtkAdjustment *pos = NULL;
1072 g_return_if_fail(folder != NULL);
1074 if (!folder->klass->scan_tree) return;
1078 window = label_window_create(_("Scanning folder tree..."));
1081 folderview = mainwin->folderview;
1084 pos = gtk_scrolled_window_get_vadjustment(
1085 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1086 height = pos->value;
1089 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1090 folder_fast_scan_tree(folder);
1091 folder_set_ui_func(folder, NULL, NULL);
1093 folderview_set_all();
1096 pos = gtk_scrolled_window_get_vadjustment(
1097 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1098 gtk_adjustment_set_value(pos, height);
1100 gtk_widget_destroy(window);
1104 /** folderview_check_new()
1105 * Scan and update the folder and return the
1106 * count the number of new messages since last check.
1107 * \param folder the folder to check for new messages
1108 * \return the number of new messages since last check
1110 gint folderview_check_new(Folder *folder)
1114 FolderView *folderview;
1118 gint former_new_msgs = 0;
1119 gint former_new = 0, former_unread = 0, former_total;
1121 for (list = folderview_list; list != NULL; list = list->next) {
1122 folderview = (FolderView *)list->data;
1123 ctree = GTK_CTREE(folderview->ctree);
1126 main_window_lock(folderview->mainwin);
1128 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1129 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1131 item = gtk_ctree_node_get_row_data(ctree, node);
1132 if (!item || !item->path || !item->folder) continue;
1133 if (item->no_select) continue;
1134 if (folder && folder != item->folder) continue;
1135 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1136 if (!item->prefs->newmailcheck) continue;
1137 if (item->processing_pending == TRUE) {
1138 debug_print("skipping %s, processing pending\n",
1139 item->path ? item->path : item->name);
1143 str = get_scan_str(item);
1145 STATUSBAR_PUSH(folderview->mainwin, str);
1149 folderview_scan_tree_func(item->folder, item, NULL);
1150 former_new = item->new_msgs;
1151 former_unread = item->unread_msgs;
1152 former_total = item->total_msgs;
1154 if (item->folder->klass->scan_required &&
1155 (item->folder->klass->scan_required(item->folder, item) ||
1156 item->folder->inbox == item ||
1157 item->opened == TRUE ||
1158 item->processing_pending == TRUE)) {
1159 if (folder_item_scan(item) < 0) {
1161 summaryview_unlock(folderview->summaryview, item);
1162 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1163 log_error(_("Couldn't scan folder %s\n"),
1164 item->path ? item->path:item->name);
1166 } else if (!FOLDER_IS_LOCAL(folder)) {
1167 STATUSBAR_POP(folderview->mainwin);
1172 } else if (!item->folder->klass->scan_required) {
1173 if (folder_item_scan(item) < 0) {
1174 summaryview_unlock(folderview->summaryview, item);
1175 if (folder && !FOLDER_IS_LOCAL(folder)) {
1176 STATUSBAR_POP(folderview->mainwin);
1181 if (former_new != item->new_msgs ||
1182 former_unread != item->unread_msgs ||
1183 former_total != item->total_msgs)
1184 folderview_update_node(folderview, node);
1186 new_msgs += item->new_msgs;
1187 former_new_msgs += former_new;
1188 STATUSBAR_POP(folderview->mainwin);
1191 main_window_unlock(folderview->mainwin);
1195 folder_write_list();
1196 /* Number of new messages since last check is the just the difference
1197 * between former_new_msgs and new_msgs. If new_msgs is less than
1198 * former_new_msgs, that would mean another session accessed the folder
1199 * and the result is not well defined.
1201 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1205 void folderview_check_new_all(void)
1209 FolderView *folderview;
1211 folderview = (FolderView *)folderview_list->data;
1214 main_window_lock(folderview->mainwin);
1215 window = label_window_create
1216 (_("Checking for new messages in all folders..."));
1218 list = folder_get_list();
1219 for (; list != NULL; list = list->next) {
1220 Folder *folder = list->data;
1222 folderview_check_new(folder);
1225 folder_write_list();
1226 folderview_set_all();
1228 gtk_widget_destroy(window);
1229 main_window_unlock(folderview->mainwin);
1233 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1239 if (!item || !item->folder || !item->folder->node)
1242 node = item->folder->node;
1244 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1245 node = node->children;
1248 (item->new_msgs > 0 ||
1249 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1253 while (node != NULL) {
1254 if (node && node->data) {
1255 FolderItem *next_item = (FolderItem*) node->data;
1257 if (folderview_have_new_children_sub(folderview,
1266 static gboolean folderview_have_new_children(FolderView *folderview,
1269 return folderview_have_new_children_sub(folderview, item, FALSE);
1272 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1278 if (!item || !item->folder || !item->folder->node)
1281 node = item->folder->node;
1283 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1284 node = node->children;
1287 (item->unread_msgs > 0 ||
1288 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1292 while (node != NULL) {
1293 if (node && node->data) {
1294 FolderItem *next_item = (FolderItem*) node->data;
1296 if (folderview_have_unread_children_sub(folderview,
1306 static gboolean folderview_have_unread_children(FolderView *folderview,
1309 return folderview_have_unread_children_sub(folderview, item, FALSE);
1312 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1318 if (!item || !item->folder || !item->folder->node)
1321 node = item->folder->node;
1323 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1324 node = node->children;
1326 if (in_sub && item->search_match){
1330 while (node != NULL) {
1331 if (node && node->data) {
1332 FolderItem *next_item = (FolderItem*) node->data;
1334 if (folderview_have_matching_children_sub(folderview,
1344 static gboolean folderview_have_matching_children(FolderView *folderview,
1347 return folderview_have_matching_children_sub(folderview, item, FALSE);
1350 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1356 if (!item || !item->folder || !item->folder->node)
1359 node = item->folder->node;
1361 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1362 node = node->children;
1364 if (item->marked_msgs != 0) {
1368 while (node != NULL) {
1369 if (node && node->data) {
1370 FolderItem *next_item = (FolderItem*) node->data;
1372 if (folderview_have_marked_children_sub(folderview,
1381 static gboolean folderview_have_marked_children(FolderView *folderview,
1384 return folderview_have_marked_children_sub(folderview, item, FALSE);
1387 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1389 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1390 GtkStyle *style = NULL;
1391 GtkStyle *color_style = NULL;
1393 GdkPixmap *xpm, *openxpm;
1394 GdkBitmap *mask, *openmask;
1395 static GdkPixmap *searchicon;
1396 static GdkBitmap *searchmask;
1397 gboolean mark = FALSE;
1400 gboolean add_unread_mark;
1401 gboolean add_sub_match_mark;
1402 gboolean use_bold, use_color;
1403 gint *col_pos = folderview->col_pos;
1404 SpecialFolderItemType stype;
1406 item = gtk_ctree_node_get_row_data(ctree, node);
1407 g_return_if_fail(item != NULL);
1409 if (!GTK_CTREE_ROW(node)->expanded)
1410 mark = folderview_have_marked_children(folderview, item);
1412 mark = (item->marked_msgs != 0);
1414 stype = item->stype;
1415 if (stype == F_NORMAL) {
1416 if (folder_has_parent_of_type(item, F_TRASH))
1418 else if (folder_has_parent_of_type(item, F_DRAFT))
1420 else if (folder_has_parent_of_type(item, F_OUTBOX))
1422 else if (folder_has_parent_of_type(item, F_QUEUE))
1427 if (item->hide_read_msgs) {
1428 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1429 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1430 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1431 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1433 xpm = mark?m_inboxxpm:inboxxpm;
1434 mask = mark?m_inboxxpmmask:inboxxpmmask;
1435 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1436 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1440 if (item->hide_read_msgs) {
1441 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1442 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1443 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1444 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1446 xpm = mark?m_outboxxpm:outboxxpm;
1447 mask = mark?m_outboxxpmmask:outboxxpmmask;
1448 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1449 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1453 if (item->hide_read_msgs) {
1454 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1455 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1456 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1457 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1459 xpm = mark?m_queuexpm:queuexpm;
1460 mask = mark?m_queuexpmmask:queuexpmmask;
1461 openxpm = mark?m_queueopenxpm:queueopenxpm;
1462 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1466 if (item->hide_read_msgs) {
1467 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1468 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1469 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1470 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1472 xpm = mark?m_trashxpm:trashxpm;
1473 mask = mark?m_trashxpmmask:trashxpmmask;
1474 openxpm = mark?m_trashopenxpm:trashopenxpm;
1475 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1479 xpm = mark?m_draftsxpm:draftsxpm;
1480 mask = mark?m_draftsxpmmask:draftsxpmmask;
1481 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1482 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1485 if (item->hide_read_msgs) {
1486 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1487 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1488 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1489 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1491 xpm = mark?m_folderxpm:folderxpm;
1492 mask = mark?m_folderxpmmask:folderxpmmask;
1493 openxpm = mark?m_folderopenxpm:folderopenxpm;
1494 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1498 if (item->no_select) {
1499 xpm = openxpm = noselectxpm;
1500 mask = openmask = noselectxpmmask;
1503 name = folder_item_get_name(item);
1505 if (!GTK_CTREE_ROW(node)->expanded) {
1506 add_unread_mark = folderview_have_unread_children(
1508 add_sub_match_mark = folderview_have_matching_children(
1511 add_unread_mark = FALSE;
1512 add_sub_match_mark = FALSE;
1515 if (item->search_match) {
1517 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1518 &searchicon, &searchmask);
1520 xpm = openxpm = searchicon;
1521 mask = openmask = searchmask;
1524 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1525 prefs_common.display_folder_unread) {
1526 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1527 add_unread_mark ? "+" : "");
1528 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1529 xpm, mask, openxpm, openmask,
1530 FALSE, GTK_CTREE_ROW(node)->expanded);
1532 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1533 prefs_common.display_folder_unread)
1534 || add_sub_match_mark) {
1536 if (item->unread_msgs > 0)
1537 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1538 add_unread_mark || add_sub_match_mark ? "+" : "",
1539 item->unreadmarked_msgs > 0 ? "!":"");
1541 str = g_strdup_printf("%s (+)", name);
1542 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1543 xpm, mask, openxpm, openmask,
1544 FALSE, GTK_CTREE_ROW(node)->expanded);
1547 str = g_strdup_printf("%s%s", name,
1548 item->unreadmarked_msgs > 0 ? " (!)":"");
1550 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1551 xpm, mask, openxpm, openmask,
1552 FALSE, GTK_CTREE_ROW(node)->expanded);
1557 if (!folder_item_parent(item)) {
1558 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1559 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1560 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1562 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1563 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1564 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1567 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1568 folder_has_parent_of_type(item, F_DRAFT) ||
1569 folder_has_parent_of_type(item, F_TRASH)) {
1570 use_bold = use_color = FALSE;
1571 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1572 /* highlight queue folder if there are any messages */
1573 use_bold = use_color = (item->total_msgs > 0);
1575 /* if unread messages exist, print with bold font */
1576 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1578 /* if new messages exist, print with colored letter */
1580 (item->new_msgs > 0) ||
1582 folderview_have_new_children(folderview, item));
1585 gtk_ctree_node_set_foreground(ctree, node, NULL);
1590 if (item->prefs->color > 0 && !use_color) {
1591 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1592 color_style = gtk_style_copy(bold_style);
1593 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1594 style = color_style;
1595 } else if (use_color) {
1596 style = bold_color_style;
1599 if (item->op_count > 0) {
1600 style = bold_tgtfold_style;
1602 } else if (use_color) {
1603 style = normal_color_style;
1604 gtk_ctree_node_set_foreground(ctree, node,
1605 &folderview->color_new);
1606 } else if (item->op_count > 0) {
1607 style = bold_tgtfold_style;
1608 } else if (item->prefs->color > 0) {
1610 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1611 color_style = gtk_style_copy(normal_style);
1612 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1613 style = color_style;
1615 style = normal_style;
1618 gtk_ctree_node_set_row_style(ctree, node, style);
1620 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1621 folderview_update_node(folderview, node);
1624 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1627 FolderView *folderview;
1631 g_return_if_fail(item != NULL);
1633 for (list = folderview_list; list != NULL; list = list->next) {
1634 folderview = (FolderView *)list->data;
1635 ctree = GTK_CTREE(folderview->ctree);
1637 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1639 item->search_match = matches;
1640 folderview_update_node(folderview, node);
1645 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1647 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1648 FolderView *folderview = (FolderView *)data;
1651 g_return_val_if_fail(update_info != NULL, TRUE);
1652 g_return_val_if_fail(update_info->item != NULL, TRUE);
1653 g_return_val_if_fail(folderview != NULL, FALSE);
1655 ctree = GTK_CTREE(folderview->ctree);
1657 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1660 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1661 folderview_update_node(folderview, node);
1662 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1663 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1664 summary_show(folderview->summaryview, update_info->item);
1670 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1671 GNode *gnode, GtkCTreeNode *cnode,
1674 FolderView *folderview = (FolderView *)data;
1675 FolderItem *item = FOLDER_ITEM(gnode->data);
1677 g_return_val_if_fail(item != NULL, FALSE);
1679 gtk_ctree_node_set_row_data(ctree, cnode, item);
1680 folderview_update_node(folderview, cnode);
1685 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1688 FolderView *folderview = (FolderView *)data;
1691 if (GTK_CTREE_ROW(node)->children) {
1692 item = gtk_ctree_node_get_row_data(ctree, node);
1693 g_return_if_fail(item != NULL);
1695 if (!item->collapsed)
1696 gtk_ctree_expand(ctree, node);
1698 folderview_update_node(folderview, node);
1702 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1703 GtkCTreeNode *root, GtkCTreeNode **prev)
1706 GtkCTreeNode *node, *parent, *sibling;
1708 node = gtk_ctree_find_by_row_data(ctree, root, item);
1710 g_warning("%s not found.\n", item->path);
1712 parent = GTK_CTREE_ROW(node)->parent;
1713 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1714 sibling = GTK_CTREE_ROW(*prev)->sibling;
1716 sibling = GTK_CTREE_ROW(parent)->children;
1720 tmp = gtk_ctree_node_get_row_data
1722 if (tmp->stype != F_NORMAL)
1723 sibling = GTK_CTREE_ROW(sibling)->sibling;
1727 if (node != sibling)
1728 gtk_ctree_move(ctree, node, parent, sibling);
1735 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1738 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1739 GtkCTreeNode *prev = NULL;
1741 gtk_clist_freeze(GTK_CLIST(ctree));
1742 gtk_sctree_sort_recursive(ctree, root);
1743 if (root && GTK_CTREE_ROW(root)->parent) {
1744 gtk_clist_thaw(GTK_CLIST(ctree));
1747 set_special_folder(ctree, folder->inbox, root, &prev);
1748 set_special_folder(ctree, folder->outbox, root, &prev);
1749 set_special_folder(ctree, folder->draft, root, &prev);
1750 set_special_folder(ctree, folder->queue, root, &prev);
1751 set_special_folder(ctree, folder->trash, root, &prev);
1752 gtk_clist_thaw(GTK_CLIST(ctree));
1755 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1757 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1760 g_return_if_fail(folder != NULL);
1762 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1763 folderview_gnode_func, folderview);
1764 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1766 folderview_sort_folders(folderview, root, folder);
1769 /* callback functions */
1770 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1771 GdkEventButton *event)
1773 GtkCList *clist = GTK_CLIST(folderview->ctree);
1776 FolderViewPopup *fpopup;
1777 GtkItemFactory *fpopup_factory;
1779 FolderItem *special_trash = NULL, *special_queue = NULL;
1783 item = gtk_clist_get_row_data(clist, row);
1785 item = folderview_get_selected_item(folderview);
1787 g_return_if_fail(item != NULL);
1788 g_return_if_fail(item->folder != NULL);
1789 folder = item->folder;
1791 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1793 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1795 fpopup = g_hash_table_lookup(folderview_popups, "common");
1796 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1799 if (fpopup->set_sensitivity != NULL)
1800 fpopup->set_sensitivity(fpopup_factory, item);
1802 if (NULL != (ac = account_find_from_item(item))) {
1803 special_trash = account_get_special_folder(ac, F_TRASH);
1804 special_queue = account_get_special_folder(ac, F_QUEUE);
1807 if ((item == folder->trash || item == special_trash
1808 || folder_has_parent_of_type(item, F_TRASH)) &&
1809 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1810 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1811 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1812 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1813 && !folder_has_parent_of_type(item, F_TRASH)) {
1814 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1815 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1818 if ((item == folder->queue || item == special_queue
1819 || folder_has_parent_of_type(item, F_QUEUE)) &&
1820 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1821 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1822 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1823 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1824 && !folder_has_parent_of_type(item, F_QUEUE)) {
1825 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1826 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1829 #define SET_SENS(name, sens) \
1830 menu_set_sensitive(fpopup_factory, name, sens)
1832 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1833 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1834 folderview->selected == folderview->opened);
1835 SET_SENS("/Properties...", TRUE);
1836 SET_SENS("/Processing...", item->node->parent != NULL);
1837 if (item == folder->trash || item == special_trash
1838 || folder_has_parent_of_type(item, F_TRASH)) {
1839 GSList *msglist = folder_item_get_msg_list(item);
1840 SET_SENS("/Empty trash...", msglist != NULL);
1841 procmsg_msg_list_free(msglist);
1843 if (item == folder->queue || item == special_queue
1844 || folder_has_parent_of_type(item, F_QUEUE)) {
1845 GSList *msglist = folder_item_get_msg_list(item);
1846 SET_SENS("/Send queue...", msglist != NULL);
1847 procmsg_msg_list_free(msglist);
1851 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1852 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1853 event->button, event->time);
1858 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1859 FolderView *folderview)
1861 GtkCList *clist = GTK_CLIST(ctree);
1862 gint prev_row = -1, row = -1, column = -1;
1864 if (!event) return FALSE;
1866 if (event->button == 1 || event->button == 2) {
1867 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1868 folderview->open_folder = TRUE;
1870 if (event->type == GDK_2BUTTON_PRESS) {
1871 if (clist->selection) {
1874 node = GTK_CTREE_NODE(clist->selection->data);
1876 gtk_ctree_toggle_expansion(
1879 folderview->open_folder = FALSE;
1886 if (event->button == 2 || event->button == 3) {
1888 if (clist->selection) {
1891 node = GTK_CTREE_NODE(clist->selection->data);
1893 prev_row = gtkut_ctree_get_nth_from_node
1894 (GTK_CTREE(ctree), node);
1897 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1900 if (prev_row != row) {
1901 gtk_clist_unselect_all(clist);
1902 if (event->button == 2)
1903 folderview_select_node
1905 gtk_ctree_node_nth(GTK_CTREE(ctree),
1908 gtk_clist_select_row(clist, row, column);
1912 if (event->button != 3) return FALSE;
1914 folderview_set_sens_and_popup_menu(folderview, row, event);
1918 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1919 FolderView *folderview)
1921 if (!event) return FALSE;
1923 if (event->button == 1 && folderview->open_folder == FALSE &&
1924 folderview->opened != NULL) {
1925 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1926 folderview->opened);
1927 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1933 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1934 FolderView *folderview)
1936 if (!event) return FALSE;
1938 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1941 switch (event->keyval) {
1943 if (folderview->selected) {
1944 folderview_select_node(folderview,
1945 folderview->selected);
1949 if (folderview->selected) {
1950 if (folderview->opened == folderview->selected &&
1951 (!folderview->summaryview->folder_item ||
1952 folderview->summaryview->folder_item->total_msgs == 0))
1953 folderview_select_next_unread(folderview, TRUE);
1955 folderview_select_node(folderview,
1956 folderview->selected);
1966 typedef struct _PostponedSelectData
1971 FolderView *folderview;
1972 } PostponedSelectData;
1974 static gboolean postpone_select(void *data)
1976 PostponedSelectData *psdata = (PostponedSelectData *)data;
1977 debug_print("trying again\n");
1978 psdata->folderview->open_folder = TRUE;
1979 main_window_cursor_normal(psdata->folderview->mainwin);
1980 STATUSBAR_POP(psdata->folderview->mainwin);
1981 folderview_selected(psdata->ctree, psdata->row,
1982 psdata->column, psdata->folderview);
1987 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1988 gint column, FolderView *folderview)
1990 static gboolean can_select = TRUE; /* exclusive lock */
1996 folderview->selected = row;
1998 if (folderview->opened == row) {
1999 folderview->open_folder = FALSE;
2004 if (!can_select || summary_is_locked(folderview->summaryview)) {
2005 if (folderview->opened) {
2006 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2007 gtk_ctree_select(ctree, folderview->opened);
2013 if (!folderview->open_folder) {
2017 item = gtk_ctree_node_get_row_data(ctree, row);
2018 if (!item || item->no_select) {
2020 folderview->open_folder = FALSE;
2026 /* Save cache for old folder */
2027 /* We don't want to lose all caches if sylpheed crashed */
2028 if (folderview->opened) {
2029 FolderItem *olditem;
2031 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2033 buf = g_strdup_printf(_("Closing Folder %s..."),
2034 olditem->path ? olditem->path:olditem->name);
2035 /* will be null if we just moved the previously opened folder */
2036 STATUSBAR_PUSH(folderview->mainwin, buf);
2037 main_window_cursor_wait(folderview->mainwin);
2039 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2040 summary_show(folderview->summaryview, NULL);
2041 folder_item_close(olditem);
2042 main_window_cursor_normal(folderview->mainwin);
2043 STATUSBAR_POP(folderview->mainwin);
2047 /* CLAWS: set compose button type: news folder items
2048 * always have a news folder as parent */
2050 toolbar_set_compose_button
2051 (folderview->mainwin->toolbar,
2052 FOLDER_TYPE(item->folder) == F_NEWS ?
2053 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2056 debug_print("Folder %s is selected\n", item->path);
2058 if (!GTK_CTREE_ROW(row)->children)
2059 gtk_ctree_expand(ctree, row);
2060 if (folderview->opened &&
2061 !GTK_CTREE_ROW(folderview->opened)->children)
2062 gtk_ctree_collapse(ctree, folderview->opened);
2064 /* ungrab the mouse event */
2065 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2066 gtk_grab_remove(GTK_WIDGET(ctree));
2067 if (gdk_pointer_is_grabbed())
2068 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2072 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2073 item->path : "(null)");
2074 debug_print("%s\n", buf);
2075 STATUSBAR_PUSH(folderview->mainwin, buf);
2078 main_window_cursor_wait(folderview->mainwin);
2080 res = folder_item_open(item);
2082 main_window_cursor_normal(folderview->mainwin);
2083 STATUSBAR_POP(folderview->mainwin);
2085 alertpanel_error(_("Folder could not be opened."));
2087 folderview->open_folder = FALSE;
2091 } else if (res == -2) {
2092 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2093 data->ctree = ctree;
2095 data->column = column;
2096 data->folderview = folderview;
2097 debug_print("postponing open of %s till end of scan\n",
2098 item->path ? item->path:item->name);
2099 folderview->open_folder = FALSE;
2101 g_timeout_add(500, postpone_select, data);
2106 main_window_cursor_normal(folderview->mainwin);
2109 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2110 opened = summary_show(folderview->summaryview, item);
2112 folder_clean_cache_memory(item);
2115 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2116 gtk_ctree_select(ctree, folderview->opened);
2118 folderview->opened = row;
2119 if (gtk_ctree_node_is_visible(ctree, row)
2120 != GTK_VISIBILITY_FULL)
2121 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2124 STATUSBAR_POP(folderview->mainwin);
2126 folderview->open_folder = FALSE;
2131 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2132 FolderView *folderview)
2136 item = gtk_ctree_node_get_row_data(ctree, node);
2137 g_return_if_fail(item != NULL);
2138 item->collapsed = FALSE;
2139 folderview_update_node(folderview, node);
2142 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2143 FolderView *folderview)
2147 item = gtk_ctree_node_get_row_data(ctree, node);
2148 g_return_if_fail(item != NULL);
2149 item->collapsed = TRUE;
2150 folderview_update_node(folderview, node);
2153 static void folderview_popup_close(GtkMenuShell *menu_shell,
2154 FolderView *folderview)
2156 if (!folderview->opened) return;
2158 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2161 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2162 FolderView *folderview)
2164 FolderColumnType type = folderview->col_state[column].type;
2166 prefs_common.folder_col_size[type] = width;
2169 static void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2173 folderview_create_folder_node(folderview, item);
2175 if (!item || !item->folder || !item->folder->node)
2178 srcnode = item->folder->node;
2179 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2180 srcnode = srcnode->children;
2181 while (srcnode != NULL) {
2182 if (srcnode && srcnode->data) {
2183 FolderItem *next_item = (FolderItem*) srcnode->data;
2184 folderview_create_folder_node_recursive(folderview, next_item);
2186 srcnode = srcnode->next;
2190 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2192 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2193 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2194 GtkCTreeNode *node, *parent_node;
2195 gint *col_pos = folderview->col_pos;
2196 FolderItemUpdateData hookdata;
2198 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2199 if (parent_node == NULL)
2202 gtk_clist_freeze(GTK_CLIST(ctree));
2204 text[col_pos[F_COL_FOLDER]] = item->name;
2205 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2207 folderxpm, folderxpmmask,
2208 folderopenxpm, folderopenxpmmask,
2210 gtk_ctree_expand(ctree, parent_node);
2211 gtk_ctree_node_set_row_data(ctree, node, item);
2213 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2214 folderview_sort_folders(folderview, parent_node, item->folder);
2216 hookdata.item = item;
2217 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2218 hookdata.msg = NULL;
2219 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2221 gtk_clist_thaw(GTK_CLIST(ctree));
2224 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2227 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2229 GSList *mlist = NULL;
2231 FolderItem *special_trash = NULL;
2234 if (!folderview->selected) return;
2235 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2236 g_return_if_fail(item != NULL);
2237 g_return_if_fail(item->folder != NULL);
2239 if (NULL != (ac = account_find_from_item(item)))
2240 special_trash = account_get_special_folder(ac, F_TRASH);
2242 if (item != item->folder->trash && item != special_trash
2243 && !folder_has_parent_of_type(item, F_TRASH)) return;
2245 if (prefs_common.ask_on_clean) {
2246 if (alertpanel(_("Empty trash"),
2247 _("Delete all messages in trash?"),
2248 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2252 mlist = folder_item_get_msg_list(item);
2254 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2255 MsgInfo * msginfo = (MsgInfo *) cur->data;
2256 if (MSG_IS_LOCKED(msginfo->flags))
2258 /* is it partially received? (partial_recv isn't cached) */
2259 if (msginfo->total_size != 0 &&
2260 msginfo->size != (off_t)msginfo->total_size)
2261 partial_mark_for_delete(msginfo);
2263 procmsg_msg_list_free(mlist);
2265 folder_item_remove_all_msg(item);
2268 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2271 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2273 FolderItem *special_queue = NULL;
2275 gchar *errstr = NULL;
2277 if (!folderview->selected) return;
2278 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2279 g_return_if_fail(item != NULL);
2280 g_return_if_fail(item->folder != NULL);
2282 if (NULL != (ac = account_find_from_item(item)))
2283 special_queue = account_get_special_folder(ac, F_QUEUE);
2285 if (item != item->folder->queue && item != special_queue
2286 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2288 if (procmsg_queue_is_empty(item))
2291 if (prefs_common.work_offline)
2292 if (alertpanel(_("Offline warning"),
2293 _("You're working offline. Override?"),
2294 GTK_STOCK_NO, GTK_STOCK_YES,
2295 NULL) != G_ALERTALTERNATE)
2298 /* ask for confirmation before sending queued messages only
2299 in online mode and if there is at least one message queued
2300 in any of the folder queue
2302 if (prefs_common.confirm_send_queued_messages) {
2303 if (!prefs_common.work_offline) {
2304 if (alertpanel(_("Send queued messages"),
2305 _("Send all queued messages?"),
2306 GTK_STOCK_CANCEL, _("_Send"),
2307 NULL) != G_ALERTALTERNATE)
2312 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2314 alertpanel_error_log(_("Some errors occurred while "
2315 "sending queued messages."));
2317 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2318 "while sending queued messages:\n%s"), errstr);
2320 alertpanel_error_log(tmp);
2326 static void folderview_search_cb(FolderView *folderview, guint action,
2329 summary_search(folderview->summaryview);
2332 static void folderview_property_cb(FolderView *folderview, guint action,
2335 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2338 if (!folderview->selected) return;
2340 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2341 g_return_if_fail(item != NULL);
2342 g_return_if_fail(item->folder != NULL);
2344 prefs_folder_item_open(item);
2347 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2349 GSList *list = NULL;
2350 GSList *done = NULL;
2351 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2353 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2354 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2355 && list->data != node) {
2356 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2357 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2360 for (list = done; list != NULL; list = g_slist_next(list)) {
2361 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2367 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2368 FolderItem *to_folder, gboolean copy)
2370 FolderItem *from_parent = NULL;
2371 FolderItem *new_folder = NULL;
2372 GtkCTreeNode *src_node = NULL;
2376 g_return_if_fail(folderview != NULL);
2377 g_return_if_fail(from_folder != NULL);
2378 g_return_if_fail(to_folder != NULL);
2380 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2381 from_parent = folder_item_parent(from_folder);
2383 if (prefs_common.warn_dnd) {
2384 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2385 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2386 from_folder->name, to_folder->name);
2387 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2388 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2389 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2392 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2394 else if (status & G_ALERTDISABLE)
2395 prefs_common.warn_dnd = FALSE;
2398 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2399 from_folder->name, to_folder->name);
2400 STATUSBAR_PUSH(folderview->mainwin, buf);
2402 summary_clear_all(folderview->summaryview);
2403 folderview->opened = NULL;
2404 folderview->selected = NULL;
2405 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2407 main_window_cursor_wait(folderview->mainwin);
2409 statusbar_verbosity_set(FALSE);
2410 folder_item_update_freeze();
2411 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2412 statusbar_verbosity_set(FALSE);
2413 main_window_cursor_normal(folderview->mainwin);
2414 STATUSBAR_POP(folderview->mainwin);
2415 folder_item_update_thaw();
2416 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2418 folderview_sort_folders(folderview,
2419 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2420 NULL, to_folder), new_folder->folder);
2421 folderview_select(folderview, new_folder);
2423 statusbar_verbosity_set(FALSE);
2424 main_window_cursor_normal(folderview->mainwin);
2425 STATUSBAR_POP(folderview->mainwin);
2426 folder_item_update_thaw();
2428 case F_MOVE_FAILED_DEST_IS_PARENT:
2429 alertpanel_error(_("Source and destination are the same."));
2431 case F_MOVE_FAILED_DEST_IS_CHILD:
2432 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2433 _("Can't move a folder to one of its children."));
2435 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2436 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2439 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2444 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2447 static gint folderview_clist_compare(GtkCList *clist,
2448 gconstpointer ptr1, gconstpointer ptr2)
2450 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2451 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2454 return (item2->name != NULL);
2458 return g_utf8_collate(item1->name, item2->name);
2461 static void folderview_processing_cb(FolderView *folderview, guint action,
2464 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2468 if (!folderview->selected) return;
2470 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2471 g_return_if_fail(item != NULL);
2472 g_return_if_fail(item->folder != NULL);
2474 id = folder_item_get_identifier(item);
2475 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2478 prefs_filtering_open(&item->prefs->processing, title,
2479 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2483 void folderview_set_target_folder_color(gint color_op)
2487 FolderView *folderview;
2489 for (list = folderview_list; list != NULL; list = list->next) {
2490 folderview = (FolderView *)list->data;
2491 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2493 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2494 folderview->color_op;
2500 static gchar *last_font = NULL;
2501 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2509 void folderview_reflect_prefs(void)
2511 gboolean update_font = TRUE;
2512 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2513 FolderItem *item = folderview_get_selected_item(folderview);
2514 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2515 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2516 gint height = pos->value;
2518 if (last_font && !strcmp(last_font, NORMAL_FONT))
2519 update_font = FALSE;
2522 last_font = g_strdup(NORMAL_FONT);
2525 normal_style = normal_color_style = bold_style =
2526 bold_color_style = bold_tgtfold_style = NULL;
2528 folderview_init(folderview);
2530 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2531 folderview_column_set_titles(folderview);
2532 folderview_set_all();
2534 g_signal_handlers_block_by_func
2535 (G_OBJECT(folderview->ctree),
2536 G_CALLBACK(folderview_selected), folderview);
2539 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2540 GTK_CTREE(folderview->ctree), NULL, item);
2542 folderview_select(folderview, item);
2543 folderview->open_folder = FALSE;
2544 folderview->selected = node;
2547 g_signal_handlers_unblock_by_func
2548 (G_OBJECT(folderview->ctree),
2549 G_CALLBACK(folderview_selected), folderview);
2551 pos = gtk_scrolled_window_get_vadjustment(
2552 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2553 gtk_adjustment_set_value(pos, height);
2554 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2557 static void drag_state_stop(FolderView *folderview)
2559 if (folderview->drag_timer)
2560 g_source_remove(folderview->drag_timer);
2561 folderview->drag_timer = 0;
2562 folderview->drag_node = NULL;
2565 static gint folderview_defer_expand(FolderView *folderview)
2567 if (folderview->drag_node) {
2568 folderview_recollapse_nodes(folderview, folderview->drag_node);
2569 if (folderview->drag_item->collapsed) {
2570 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2571 folderview->nodes_to_recollapse = g_slist_append
2572 (folderview->nodes_to_recollapse, folderview->drag_node);
2575 folderview->drag_item = NULL;
2576 folderview->drag_timer = 0;
2580 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2582 /* the idea is that we call drag_state_start() whenever we want expansion to
2583 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2584 * we need to call drag_state_stop() */
2585 drag_state_stop(folderview);
2586 /* request expansion */
2587 if (0 != (folderview->drag_timer = g_timeout_add
2588 (prefs_common.hover_timeout,
2589 (GtkFunction)folderview_defer_expand,
2591 folderview->drag_node = node;
2592 folderview->drag_item = item;
2596 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2597 FolderView *folderview)
2599 GdkDragContext *context;
2601 g_return_if_fail(folderview != NULL);
2602 if (folderview->selected == NULL) return;
2603 if (folderview->nodes_to_recollapse)
2604 g_slist_free(folderview->nodes_to_recollapse);
2605 folderview->nodes_to_recollapse = NULL;
2606 context = gtk_drag_begin(widget, folderview->target_list,
2607 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2608 gtk_drag_set_icon_default(context);
2611 static void folderview_drag_data_get(GtkWidget *widget,
2612 GdkDragContext *drag_context,
2613 GtkSelectionData *selection_data,
2616 FolderView *folderview)
2620 gchar *source = NULL;
2621 if (info == TARGET_DUMMY) {
2622 for (cur = GTK_CLIST(folderview->ctree)->selection;
2623 cur != NULL; cur = cur->next) {
2624 item = gtk_ctree_node_get_row_data
2625 (GTK_CTREE(folderview->ctree),
2626 GTK_CTREE_NODE(cur->data));
2628 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2629 gtk_selection_data_set(selection_data,
2630 selection_data->target, 8,
2631 source, strlen(source));
2637 g_warning("unknown info %d\n", info);
2641 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2643 FolderUpdateData *hookdata;
2644 FolderView *folderview;
2648 folderview = (FolderView *) userdata;
2649 g_return_val_if_fail(hookdata != NULL, FALSE);
2650 g_return_val_if_fail(folderview != NULL, FALSE);
2652 ctree = folderview->ctree;
2653 g_return_val_if_fail(ctree != NULL, FALSE);
2655 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2656 folderview_create_folder_node(folderview, hookdata->item);
2657 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2658 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2659 NULL, folder_item_parent(hookdata->item));
2660 folderview_sort_folders(folderview, node, hookdata->folder);
2661 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2664 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2666 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2667 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2668 folderview_set(folderview);
2673 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2674 GdkDragContext *context,
2678 FolderView *folderview)
2681 FolderItem *item = NULL, *src_item = NULL;
2682 GtkCTreeNode *node = NULL;
2683 gboolean acceptable = FALSE;
2684 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2685 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2686 int height = (int)pos->page_size;
2687 int total_height = (int)pos->upper;
2688 int vpos = (int) pos->value;
2690 if (gtk_clist_get_selection_info
2691 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2692 GtkWidget *srcwidget;
2694 if (y > height - 24 && height + vpos < total_height)
2695 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2697 if (y < 48 && y > 0)
2698 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2700 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2701 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2702 src_item = folderview->summaryview->folder_item;
2704 srcwidget = gtk_drag_get_source_widget(context);
2705 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2706 /* comes from summaryview */
2707 /* we are copying messages, so only accept folder items that are not
2708 the source item, are no root items and can copy messages */
2709 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2710 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2711 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2713 } else if (srcwidget == folderview->ctree) {
2714 /* comes from folderview */
2715 /* we are moving folder items, only accept folders that are not
2716 the source items and can copy messages and create folder items */
2717 if (item && item->folder && src_item && src_item != item &&
2718 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2719 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2720 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2721 || item->folder == src_item->folder))
2724 /* comes from another app */
2725 /* we are adding messages, so only accept folder items that are
2726 no root items and can copy messages */
2727 if (item && item->folder && folder_item_parent(item) != NULL
2728 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2729 FOLDER_TYPE(item->folder) != F_UNKNOWN)
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;
2861 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2863 source = data->data + 17;
2864 if (gtk_clist_get_selection_info
2865 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2867 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2870 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2871 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2872 src_item = folder_find_item_from_identifier(source);
2876 src_item->stype == F_NORMAL &&
2877 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2878 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2879 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2880 !folder_has_parent_of_type(src_item, F_TRASH);
2881 if (!item || item->no_select || !src_item
2882 || !folder_is_normal) {
2883 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2887 folderview_move_folder(folderview, src_item, item, copy);
2888 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2890 folderview->nodes_to_recollapse = NULL;
2891 } else if (info == TARGET_MAIL_URI_LIST) {
2892 if (gtk_clist_get_selection_info
2893 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2896 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2898 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2901 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2903 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2906 folderview_finish_dnd(data->data, drag_context, time, item);
2910 static void folderview_drag_end_cb(GtkWidget *widget,
2911 GdkDragContext *drag_context,
2912 FolderView *folderview)
2914 drag_state_stop(folderview);
2915 g_slist_free(folderview->nodes_to_recollapse);
2916 folderview->nodes_to_recollapse = NULL;
2919 void folderview_register_popup(FolderViewPopup *fpopup)
2923 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2924 FolderView *folderview = folderviews->data;
2925 GtkItemFactory *factory;
2927 factory = create_ifactory(folderview, fpopup);
2928 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2930 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2933 void folderview_unregister_popup(FolderViewPopup *fpopup)
2937 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2938 FolderView *folderview = folderviews->data;
2940 g_hash_table_remove(folderview->popups, fpopup->klass);
2942 g_hash_table_remove(folderview_popups, fpopup->klass);