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),
520 g_signal_connect(G_OBJECT(ctree), "popup-menu",
521 G_CALLBACK(folderview_popup_menu), folderview);
523 gtk_widget_tap_and_hold_setup(GTK_WIDGET(ctree), NULL, NULL,
524 GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
525 g_signal_connect(G_OBJECT(ctree), "tap-and-hold",
526 G_CALLBACK(folderview_popup_menu), folderview);
528 g_signal_connect(G_OBJECT(ctree), "button_release_event",
529 G_CALLBACK(folderview_button_released),
531 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
532 G_CALLBACK(folderview_selected), folderview);
533 g_signal_connect(G_OBJECT(ctree), "start_drag",
534 G_CALLBACK(folderview_start_drag), folderview);
535 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
536 G_CALLBACK(folderview_drag_data_get),
539 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
540 G_CALLBACK(folderview_tree_expanded),
542 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
543 G_CALLBACK(folderview_tree_collapsed),
546 g_signal_connect(G_OBJECT(ctree), "resize_column",
547 G_CALLBACK(folderview_col_resized),
551 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
552 folderview_drag_types, 2,
553 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
554 g_signal_connect(G_OBJECT(ctree), "drag_motion",
555 G_CALLBACK(folderview_drag_motion_cb),
557 g_signal_connect(G_OBJECT(ctree), "drag_leave",
558 G_CALLBACK(folderview_drag_leave_cb),
560 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
561 G_CALLBACK(folderview_drag_received_cb),
563 g_signal_connect(G_OBJECT(ctree), "drag_end",
564 G_CALLBACK(folderview_drag_end_cb),
567 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
572 void folderview_set_column_order(FolderView *folderview)
575 FolderItem *item = folderview_get_selected_item(folderview);
576 GtkWidget *scrolledwin = folderview->scrolledwin;
578 debug_print("recreating tree...\n");
579 gtk_widget_destroy(folderview->ctree);
581 folderview->ctree = ctree = folderview_ctree_create(folderview);
582 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
583 GTK_CLIST(ctree)->hadjustment);
584 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
585 GTK_CLIST(ctree)->vadjustment);
586 gtk_widget_show(ctree);
588 folderview_set(folderview);
589 folderview_column_set_titles(folderview);
591 folderview_select(folderview,item);
594 FolderView *folderview_create(void)
596 FolderView *folderview;
597 GtkWidget *scrolledwin;
600 debug_print("Creating folder view...\n");
601 folderview = g_new0(FolderView, 1);
603 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
604 gtk_scrolled_window_set_policy
605 (GTK_SCROLLED_WINDOW(scrolledwin),
606 GTK_POLICY_AUTOMATIC,
607 prefs_common.folderview_vscrollbar_policy);
608 gtk_widget_set_size_request(scrolledwin,
609 prefs_common.folderview_width,
610 prefs_common.folderview_height);
612 folderview->scrolledwin = scrolledwin;
613 ctree = folderview_ctree_create(folderview);
615 /* create popup factories */
616 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
617 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
619 folderview->ctree = ctree;
621 folderview->folder_update_callback_id =
622 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
623 folderview->folder_item_update_callback_id =
624 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
626 gtk_widget_show_all(scrolledwin);
628 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
629 folderview_list = g_list_append(folderview_list, folderview);
630 folderview->deferred_refresh_id = -1;
635 void folderview_init(FolderView *folderview)
637 GtkWidget *ctree = folderview->ctree;
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
671 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
677 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
678 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
679 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
680 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
681 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
682 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
683 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
684 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
685 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
688 PangoFontDescription *font_desc;
689 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
690 font_desc = pango_font_description_from_string(NORMAL_FONT);
692 if (normal_style->font_desc)
693 pango_font_description_free
694 (normal_style->font_desc);
695 normal_style->font_desc = font_desc;
697 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
698 normal_color_style = gtk_style_copy(normal_style);
699 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
701 gtk_widget_set_style(ctree, normal_style);
705 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
706 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
707 pango_font_description_set_weight
708 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
709 bold_color_style = gtk_style_copy(bold_style);
710 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
712 bold_tgtfold_style = gtk_style_copy(bold_style);
713 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
717 static gboolean folderview_defer_set(gpointer data)
719 FolderView *folderview = (FolderView *)data;
720 MainWindow *mainwin = folderview->mainwin;
724 if (mainwin->lock_count)
727 printf("doing deferred folderview_set now\n");
728 folderview_set(folderview);
730 folderview->deferred_refresh_id = -1;
734 void folderview_set(FolderView *folderview)
736 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
737 MainWindow *mainwin = folderview->mainwin;
738 FolderItem *sel_item = NULL, *op_item = NULL;
743 if (mainwin->lock_count) {
744 if (folderview->deferred_refresh_id == -1)
745 folderview->deferred_refresh_id =
746 g_timeout_add(500, folderview_defer_set, folderview);
747 printf("deferred folderview_set\n");
752 debug_print("Setting folder info...\n");
753 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
755 main_window_cursor_wait(mainwin);
757 if (folderview->selected)
758 sel_item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
759 if (folderview->opened)
760 op_item = gtk_ctree_node_get_row_data(ctree, folderview->opened);
762 folderview->selected = NULL;
763 folderview->opened = NULL;
765 gtk_clist_freeze(GTK_CLIST(ctree));
766 gtk_clist_clear(GTK_CLIST(ctree));
768 folderview_set_folders(folderview);
771 folderview->selected = gtk_ctree_find_by_row_data(ctree, NULL, sel_item);
773 folderview->opened = gtk_ctree_find_by_row_data(ctree, NULL, op_item);
775 gtk_clist_thaw(GTK_CLIST(ctree));
776 main_window_cursor_normal(mainwin);
777 STATUSBAR_POP(mainwin);
781 void folderview_set_all(void)
785 for (list = folderview_list; list != NULL; list = list->next)
786 folderview_set((FolderView *)list->data);
789 void folderview_select(FolderView *folderview, FolderItem *item)
791 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
793 GtkCTreeNode *old_selected = folderview->selected;
797 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
798 if (node) folderview_select_node(folderview, node);
800 if (old_selected != node)
801 folder_update_op_count();
804 static void mark_all_read_cb(FolderView *folderview, guint action,
810 item = folderview_get_selected_item(folderview);
814 if (folderview->summaryview->folder_item != item
815 && prefs_common.ask_mark_all_read) {
816 val = alertpanel_full(_("Mark all as read"),
817 _("Do you really want to mark all mails in this "
818 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
819 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
821 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
823 else if (val & G_ALERTDISABLE)
824 prefs_common.ask_mark_all_read = FALSE;
827 summary_lock(folderview->summaryview);
828 folder_item_update_freeze();
829 if (folderview->summaryview->folder_item == item)
830 summary_freeze(folderview->summaryview);
831 folderutils_mark_all_read(item);
832 if (folderview->summaryview->folder_item == item)
833 summary_thaw(folderview->summaryview);
834 folder_item_update_thaw();
835 summary_unlock(folderview->summaryview);
838 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
840 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
842 g_return_if_fail(node != NULL);
844 if (folderview->open_folder) {
848 folderview->open_folder = TRUE;
849 gtkut_ctree_set_focus_row(ctree, node);
850 gtk_ctree_select(ctree, node);
851 if (folderview->summaryview->folder_item &&
852 folderview->summaryview->folder_item->total_msgs > 0)
853 summary_grab_focus(folderview->summaryview);
855 gtk_widget_grab_focus(folderview->ctree);
857 gtkut_ctree_expand_parent_all(ctree, node);
860 void folderview_unselect(FolderView *folderview)
862 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
864 (GTK_CTREE(folderview->ctree), folderview->opened);
866 folderview->selected = folderview->opened = NULL;
869 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
875 node = gtkut_ctree_node_next(ctree, node);
877 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
879 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
880 item = gtk_ctree_node_get_row_data(ctree, node);
881 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
888 void folderview_select_next_marked(FolderView *folderview)
890 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
891 GtkCTreeNode *node = NULL;
892 SelectOnEntry last_sel = prefs_common.select_on_entry;
893 gboolean last_open = prefs_common.always_show_msg;
895 prefs_common.select_on_entry = SELECTONENTRY_MNU;
896 prefs_common.always_show_msg = TRUE;
898 if ((node = folderview_find_next_marked(ctree, folderview->opened))
900 folderview_select_node(folderview, node);
904 if (!folderview->opened ||
905 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
908 /* search again from the first node */
909 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
910 folderview_select_node(folderview, node);
913 prefs_common.select_on_entry = last_sel;
914 prefs_common.always_show_msg = last_open;
917 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
923 node = gtkut_ctree_node_next(ctree, node);
925 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
927 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
928 item = gtk_ctree_node_get_row_data(ctree, node);
929 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
936 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
938 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
939 GtkCTreeNode *node = NULL;
940 SelectOnEntry last_sel = prefs_common.select_on_entry;
941 gboolean last_open = prefs_common.always_show_msg;
943 prefs_common.select_on_entry = SELECTONENTRY_UNM;
944 prefs_common.always_show_msg = force_open ? TRUE : last_open;
946 if ((node = folderview_find_next_unread(ctree, folderview->opened))
948 folderview_select_node(folderview, node);
952 if (!folderview->opened ||
953 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
956 /* search again from the first node */
957 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
958 folderview_select_node(folderview, node);
961 prefs_common.select_on_entry = last_sel;
962 prefs_common.always_show_msg = last_open;
965 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
971 node = gtkut_ctree_node_next(ctree, node);
973 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
975 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
976 item = gtk_ctree_node_get_row_data(ctree, node);
977 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
984 void folderview_select_next_new(FolderView *folderview)
986 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
987 GtkCTreeNode *node = NULL;
988 SelectOnEntry last_sel = prefs_common.select_on_entry;
989 gboolean last_open = prefs_common.always_show_msg;
991 prefs_common.select_on_entry = SELECTONENTRY_NUM;
992 prefs_common.always_show_msg = TRUE;
994 if ((node = folderview_find_next_new(ctree, folderview->opened))
996 folderview_select_node(folderview, node);
1000 if (!folderview->opened ||
1001 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
1004 /* search again from the first node */
1005 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
1006 folderview_select_node(folderview, node);
1009 prefs_common.select_on_entry = last_sel;
1010 prefs_common.always_show_msg = last_open;
1013 FolderItem *folderview_get_selected_item(FolderView *folderview)
1015 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1017 if (!folderview->selected) return NULL;
1018 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
1021 static void folderview_set_folders(FolderView *folderview)
1024 list = folder_get_list();
1026 for (; list != NULL; list = list->next) {
1027 folderview_append_folder(folderview, FOLDER(list->data));
1031 static gchar *get_scan_str(FolderItem *item)
1034 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1035 item->folder->name, G_DIR_SEPARATOR,
1038 return g_strdup_printf(_("Scanning folder %s ..."),
1039 item->folder->name);
1041 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1045 for (list = folderview_list; list != NULL; list = list->next) {
1046 FolderView *folderview = (FolderView *)list->data;
1047 MainWindow *mainwin = folderview->mainwin;
1048 gchar *str = get_scan_str(item);
1050 STATUSBAR_PUSH(mainwin, str);
1051 STATUSBAR_POP(mainwin);
1056 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1059 MainWindow *mainwin = mainwindow_get_mainwindow();
1060 FolderView *folderview = NULL;
1061 GtkAdjustment *pos = NULL;
1064 g_return_if_fail(folder != NULL);
1066 if (!folder->klass->scan_tree) return;
1069 alertpanel_full(_("Rebuild folder tree"),
1070 _("Rebuilding the folder tree will remove "
1071 "local caches. Do you want to continue?"),
1072 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1073 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1074 != G_ALERTALTERNATE) {
1080 window = label_window_create(_("Rebuilding folder tree..."));
1082 window = label_window_create(_("Scanning folder tree..."));
1085 folderview = mainwin->folderview;
1088 pos = gtk_scrolled_window_get_vadjustment(
1089 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1090 height = pos->value;
1093 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1094 folder_scan_tree(folder, rebuild);
1095 folder_set_ui_func(folder, NULL, NULL);
1097 folderview_set_all();
1100 pos = gtk_scrolled_window_get_vadjustment(
1101 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1102 gtk_adjustment_set_value(pos, height);
1104 label_window_destroy(window);
1108 void folderview_fast_rescan_tree(Folder *folder)
1111 MainWindow *mainwin = mainwindow_get_mainwindow();
1112 FolderView *folderview = NULL;
1113 GtkAdjustment *pos = NULL;
1116 g_return_if_fail(folder != NULL);
1118 if (!folder->klass->scan_tree) return;
1122 window = label_window_create(_("Scanning folder tree..."));
1125 folderview = mainwin->folderview;
1128 pos = gtk_scrolled_window_get_vadjustment(
1129 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1130 height = pos->value;
1133 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1134 folder_fast_scan_tree(folder);
1135 folder_set_ui_func(folder, NULL, NULL);
1137 folderview_set_all();
1140 pos = gtk_scrolled_window_get_vadjustment(
1141 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1142 gtk_adjustment_set_value(pos, height);
1144 label_window_destroy(window);
1148 /** folderview_check_new()
1149 * Scan and update the folder and return the
1150 * count the number of new messages since last check.
1151 * \param folder the folder to check for new messages
1152 * \return the number of new messages since last check
1154 gint folderview_check_new(Folder *folder)
1158 FolderView *folderview;
1162 gint former_new_msgs = 0;
1163 gint former_new = 0, former_unread = 0, former_total;
1165 for (list = folderview_list; list != NULL; list = list->next) {
1166 folderview = (FolderView *)list->data;
1167 ctree = GTK_CTREE(folderview->ctree);
1170 main_window_lock(folderview->mainwin);
1172 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1173 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1175 item = gtk_ctree_node_get_row_data(ctree, node);
1176 if (!item || !item->path || !item->folder) continue;
1177 if (item->no_select) continue;
1178 if (folder && folder != item->folder) continue;
1179 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1180 if (!item->prefs->newmailcheck) continue;
1181 if (item->processing_pending == TRUE) {
1182 debug_print("skipping %s, processing pending\n",
1183 item->path ? item->path : item->name);
1187 str = get_scan_str(item);
1189 STATUSBAR_PUSH(folderview->mainwin, str);
1193 folderview_scan_tree_func(item->folder, item, NULL);
1194 former_new = item->new_msgs;
1195 former_unread = item->unread_msgs;
1196 former_total = item->total_msgs;
1198 if (item->folder->klass->scan_required &&
1199 (item->folder->klass->scan_required(item->folder, item) ||
1200 item->folder->inbox == item ||
1201 item->opened == TRUE ||
1202 item->processing_pending == TRUE)) {
1203 if (folder_item_scan(item) < 0) {
1205 summaryview_unlock(folderview->summaryview, item);
1206 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1207 log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
1208 item->path ? item->path:item->name);
1210 } else if (!FOLDER_IS_LOCAL(folder)) {
1211 STATUSBAR_POP(folderview->mainwin);
1216 } else if (!item->folder->klass->scan_required) {
1217 if (folder_item_scan(item) < 0) {
1218 summaryview_unlock(folderview->summaryview, item);
1219 if (folder && !FOLDER_IS_LOCAL(folder)) {
1220 STATUSBAR_POP(folderview->mainwin);
1225 if (former_new != item->new_msgs ||
1226 former_unread != item->unread_msgs ||
1227 former_total != item->total_msgs)
1228 folderview_update_node(folderview, node);
1230 new_msgs += item->new_msgs;
1231 former_new_msgs += former_new;
1232 STATUSBAR_POP(folderview->mainwin);
1235 main_window_unlock(folderview->mainwin);
1239 folder_write_list();
1240 /* Number of new messages since last check is the just the difference
1241 * between former_new_msgs and new_msgs. If new_msgs is less than
1242 * former_new_msgs, that would mean another session accessed the folder
1243 * and the result is not well defined.
1245 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1249 void folderview_check_new_all(void)
1253 FolderView *folderview;
1255 folderview = (FolderView *)folderview_list->data;
1258 main_window_lock(folderview->mainwin);
1259 window = label_window_create
1260 (_("Checking for new messages in all folders..."));
1262 list = folder_get_list();
1263 for (; list != NULL; list = list->next) {
1264 Folder *folder = list->data;
1266 folderview_check_new(folder);
1269 folder_write_list();
1270 folderview_set_all();
1272 label_window_destroy(window);
1273 main_window_unlock(folderview->mainwin);
1277 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1283 if (!item || !item->folder || !item->folder->node)
1286 node = item->folder->node;
1288 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1289 node = node->children;
1292 (item->new_msgs > 0 ||
1293 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1297 while (node != NULL) {
1298 if (node && node->data) {
1299 FolderItem *next_item = (FolderItem*) node->data;
1301 if (folderview_have_new_children_sub(folderview,
1310 static gboolean folderview_have_new_children(FolderView *folderview,
1313 return folderview_have_new_children_sub(folderview, item, FALSE);
1316 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1322 if (!item || !item->folder || !item->folder->node)
1325 node = item->folder->node;
1327 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1328 node = node->children;
1331 (item->unread_msgs > 0 ||
1332 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1336 while (node != NULL) {
1337 if (node && node->data) {
1338 FolderItem *next_item = (FolderItem*) node->data;
1340 if (folderview_have_unread_children_sub(folderview,
1350 static gboolean folderview_have_unread_children(FolderView *folderview,
1353 return folderview_have_unread_children_sub(folderview, item, FALSE);
1356 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1362 if (!item || !item->folder || !item->folder->node)
1365 node = item->folder->node;
1367 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1368 node = node->children;
1370 if (in_sub && item->search_match){
1374 while (node != NULL) {
1375 if (node && node->data) {
1376 FolderItem *next_item = (FolderItem*) node->data;
1378 if (folderview_have_matching_children_sub(folderview,
1388 static gboolean folderview_have_matching_children(FolderView *folderview,
1391 return folderview_have_matching_children_sub(folderview, item, FALSE);
1394 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1400 if (!item || !item->folder || !item->folder->node)
1403 node = item->folder->node;
1405 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1406 node = node->children;
1408 if (item->marked_msgs != 0) {
1412 while (node != NULL) {
1413 if (node && node->data) {
1414 FolderItem *next_item = (FolderItem*) node->data;
1416 if (folderview_have_marked_children_sub(folderview,
1425 static gboolean folderview_have_marked_children(FolderView *folderview,
1428 return folderview_have_marked_children_sub(folderview, item, FALSE);
1431 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1433 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1434 GtkStyle *style = NULL;
1435 GtkStyle *color_style = NULL;
1437 GdkPixmap *xpm, *openxpm;
1438 GdkBitmap *mask, *openmask;
1439 static GdkPixmap *searchicon;
1440 static GdkBitmap *searchmask;
1441 gboolean mark = FALSE;
1444 gboolean add_unread_mark;
1445 gboolean add_sub_match_mark;
1446 gboolean use_bold, use_color;
1447 gint *col_pos = folderview->col_pos;
1448 SpecialFolderItemType stype;
1450 item = gtk_ctree_node_get_row_data(ctree, node);
1451 g_return_if_fail(item != NULL);
1453 if (!GTK_CTREE_ROW(node)->expanded)
1454 mark = folderview_have_marked_children(folderview, item);
1456 mark = (item->marked_msgs != 0);
1458 stype = item->stype;
1459 if (stype == F_NORMAL) {
1460 if (folder_has_parent_of_type(item, F_TRASH))
1462 else if (folder_has_parent_of_type(item, F_DRAFT))
1464 else if (folder_has_parent_of_type(item, F_OUTBOX))
1466 else if (folder_has_parent_of_type(item, F_QUEUE))
1471 if (item->hide_read_msgs) {
1472 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1473 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1474 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1475 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1477 xpm = mark?m_inboxxpm:inboxxpm;
1478 mask = mark?m_inboxxpmmask:inboxxpmmask;
1479 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1480 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1484 if (item->hide_read_msgs) {
1485 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1486 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1487 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1488 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1490 xpm = mark?m_outboxxpm:outboxxpm;
1491 mask = mark?m_outboxxpmmask:outboxxpmmask;
1492 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1493 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1497 if (item->hide_read_msgs) {
1498 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1499 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1500 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1501 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1503 xpm = mark?m_queuexpm:queuexpm;
1504 mask = mark?m_queuexpmmask:queuexpmmask;
1505 openxpm = mark?m_queueopenxpm:queueopenxpm;
1506 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1510 if (item->hide_read_msgs) {
1511 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1512 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1513 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1514 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1516 xpm = mark?m_trashxpm:trashxpm;
1517 mask = mark?m_trashxpmmask:trashxpmmask;
1518 openxpm = mark?m_trashopenxpm:trashopenxpm;
1519 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1523 xpm = mark?m_draftsxpm:draftsxpm;
1524 mask = mark?m_draftsxpmmask:draftsxpmmask;
1525 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1526 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1529 if (item->hide_read_msgs) {
1530 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1531 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1532 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1533 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1535 xpm = mark?m_folderxpm:folderxpm;
1536 mask = mark?m_folderxpmmask:folderxpmmask;
1537 openxpm = mark?m_folderopenxpm:folderopenxpm;
1538 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1542 if (item->no_select) {
1543 xpm = openxpm = noselectxpm;
1544 mask = openmask = noselectxpmmask;
1547 name = folder_item_get_name(item);
1549 if (!GTK_CTREE_ROW(node)->expanded) {
1550 add_unread_mark = folderview_have_unread_children(
1552 add_sub_match_mark = folderview_have_matching_children(
1555 add_unread_mark = FALSE;
1556 add_sub_match_mark = FALSE;
1559 if (item->search_match) {
1561 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1562 &searchicon, &searchmask);
1564 xpm = openxpm = searchicon;
1565 mask = openmask = searchmask;
1569 if (prefs_common.display_folder_unread) {
1570 if (folder_has_parent_of_type(item, F_QUEUE)) {
1571 /* only total_msgs matters here */
1572 if (item->total_msgs > 0) {
1573 /* show total number (should be equal to the unread number)
1575 str = g_strdup_printf("%s (%d%s%s)",
1576 name, item->total_msgs,
1577 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1578 (item->unreadmarked_msgs > 0) ? "!" : "");
1581 if (prefs_common.display_folder_unread == 1) {
1582 if (item->unread_msgs > 0) {
1583 /* show unread number and signs */
1584 str = g_strdup_printf("%s (%d%s%s)",
1585 name, item->unread_msgs,
1586 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1587 (item->unreadmarked_msgs > 0) ? "!" : "");
1590 if (item->total_msgs > 0) {
1591 /* show unread number, total number and signs if any */
1592 str = g_strdup_printf("%s (%d/%d%s%s)",
1593 name, item->unread_msgs, item->total_msgs,
1594 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1595 (item->unreadmarked_msgs > 0) ? "!" : "");
1599 if ((str == NULL) &&
1600 (add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
1601 /* no unread/total numbers, but at least one sign */
1602 str = g_strdup_printf("%s (%s%s)",
1604 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1605 (item->unreadmarked_msgs > 0) ? "!" : "");
1609 /* last fallback, folder name only or with ! sign */
1610 str = g_strdup_printf("%s%s",
1611 name, (item->unreadmarked_msgs > 0) ? " (!)" : "");
1613 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1614 xpm, mask, openxpm, openmask,
1615 FALSE, GTK_CTREE_ROW(node)->expanded);
1619 if (!folder_item_parent(item)) {
1620 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1621 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1622 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1624 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], item->new_msgs > 0 ? itos(item->new_msgs) : prefs_common.zero_replacement);
1625 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
1626 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], item->total_msgs > 0 ? itos(item->total_msgs) : prefs_common.zero_replacement);
1629 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1630 folder_has_parent_of_type(item, F_DRAFT) ||
1631 folder_has_parent_of_type(item, F_TRASH)) {
1632 use_bold = use_color = FALSE;
1633 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1634 /* highlight queue folder if there are any messages */
1635 use_bold = use_color = (item->total_msgs > 0);
1637 /* if unread messages exist, print with bold font */
1638 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1640 /* if new messages exist, print with colored letter */
1642 (item->new_msgs > 0) ||
1644 folderview_have_new_children(folderview, item));
1647 gtk_ctree_node_set_foreground(ctree, node, NULL);
1652 if (item->prefs->color > 0 && !use_color) {
1653 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1654 color_style = gtk_style_copy(bold_style);
1655 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1656 style = color_style;
1657 } else if (use_color) {
1658 style = bold_color_style;
1661 if (item->op_count > 0) {
1662 style = bold_tgtfold_style;
1664 } else if (use_color) {
1665 style = normal_color_style;
1666 gtk_ctree_node_set_foreground(ctree, node,
1667 &folderview->color_new);
1668 } else if (item->op_count > 0) {
1669 style = bold_tgtfold_style;
1670 } else if (item->prefs->color > 0) {
1672 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1673 color_style = gtk_style_copy(normal_style);
1674 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1675 style = color_style;
1677 style = normal_style;
1680 gtk_ctree_node_set_row_style(ctree, node, style);
1682 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1683 folderview_update_node(folderview, node);
1686 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1689 FolderView *folderview;
1693 g_return_if_fail(item != NULL);
1695 for (list = folderview_list; list != NULL; list = list->next) {
1696 folderview = (FolderView *)list->data;
1697 ctree = GTK_CTREE(folderview->ctree);
1699 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1701 item->search_match = matches;
1702 folderview_update_node(folderview, node);
1707 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1709 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1710 FolderView *folderview = (FolderView *)data;
1713 g_return_val_if_fail(update_info != NULL, TRUE);
1714 g_return_val_if_fail(update_info->item != NULL, TRUE);
1715 g_return_val_if_fail(folderview != NULL, FALSE);
1717 ctree = GTK_CTREE(folderview->ctree);
1719 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1722 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1723 folderview_update_node(folderview, node);
1725 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
1726 update_info->item == folderview->summaryview->folder_item &&
1727 update_info->item != NULL)
1728 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1729 summary_show(folderview->summaryview, update_info->item);
1735 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1736 GNode *gnode, GtkCTreeNode *cnode,
1739 FolderView *folderview = (FolderView *)data;
1740 FolderItem *item = FOLDER_ITEM(gnode->data);
1742 g_return_val_if_fail(item != NULL, FALSE);
1744 gtk_ctree_node_set_row_data(ctree, cnode, item);
1745 folderview_update_node(folderview, cnode);
1750 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1753 FolderView *folderview = (FolderView *)data;
1756 if (GTK_CTREE_ROW(node)->children) {
1757 item = gtk_ctree_node_get_row_data(ctree, node);
1758 g_return_if_fail(item != NULL);
1760 if (!item->collapsed)
1761 gtk_ctree_expand(ctree, node);
1763 folderview_update_node(folderview, node);
1767 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1768 GtkCTreeNode *root, GtkCTreeNode **prev)
1771 GtkCTreeNode *node, *parent, *sibling;
1773 node = gtk_ctree_find_by_row_data(ctree, root, item);
1775 g_warning("%s not found.\n", item->path);
1777 parent = GTK_CTREE_ROW(node)->parent;
1778 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1779 sibling = GTK_CTREE_ROW(*prev)->sibling;
1781 sibling = GTK_CTREE_ROW(parent)->children;
1785 tmp = gtk_ctree_node_get_row_data
1787 if (tmp->stype != F_NORMAL)
1788 sibling = GTK_CTREE_ROW(sibling)->sibling;
1792 if (node != sibling)
1793 gtk_ctree_move(ctree, node, parent, sibling);
1800 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1803 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1804 GtkCTreeNode *prev = NULL;
1806 gtk_clist_freeze(GTK_CLIST(ctree));
1807 gtk_sctree_sort_recursive(ctree, root);
1808 if (root && GTK_CTREE_ROW(root)->parent) {
1809 gtk_clist_thaw(GTK_CLIST(ctree));
1812 set_special_folder(ctree, folder->inbox, root, &prev);
1813 set_special_folder(ctree, folder->outbox, root, &prev);
1814 set_special_folder(ctree, folder->draft, root, &prev);
1815 set_special_folder(ctree, folder->queue, root, &prev);
1816 set_special_folder(ctree, folder->trash, root, &prev);
1817 gtk_clist_thaw(GTK_CLIST(ctree));
1820 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1822 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1825 g_return_if_fail(folder != NULL);
1827 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1828 folderview_gnode_func, folderview);
1829 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1831 folderview_sort_folders(folderview, root, folder);
1834 /* callback functions */
1835 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1836 GdkEventButton *event)
1838 GtkCList *clist = GTK_CLIST(folderview->ctree);
1841 FolderViewPopup *fpopup;
1842 GtkItemFactory *fpopup_factory;
1844 FolderItem *special_trash = NULL, *special_queue = NULL;
1848 item = gtk_clist_get_row_data(clist, row);
1850 item = folderview_get_selected_item(folderview);
1852 g_return_if_fail(item != NULL);
1853 g_return_if_fail(item->folder != NULL);
1854 folder = item->folder;
1856 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1858 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1860 fpopup = g_hash_table_lookup(folderview_popups, "common");
1861 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1864 if (fpopup->set_sensitivity != NULL)
1865 fpopup->set_sensitivity(fpopup_factory, item);
1867 if (NULL != (ac = account_find_from_item(item))) {
1868 special_trash = account_get_special_folder(ac, F_TRASH);
1869 special_queue = account_get_special_folder(ac, F_QUEUE);
1872 if ((item == folder->trash || item == special_trash
1873 || folder_has_parent_of_type(item, F_TRASH)) &&
1874 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1875 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1876 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1877 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1878 && !folder_has_parent_of_type(item, F_TRASH)) {
1879 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1880 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1883 if ((item == folder->queue || item == special_queue
1884 || folder_has_parent_of_type(item, F_QUEUE)) &&
1885 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1886 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1887 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1888 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1889 && !folder_has_parent_of_type(item, F_QUEUE)) {
1890 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1891 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1894 #define SET_SENS(name, sens) \
1895 menu_set_sensitive(fpopup_factory, name, sens)
1897 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1898 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1899 folderview->selected == folderview->opened);
1900 SET_SENS("/Properties...", TRUE);
1901 SET_SENS("/Processing...", item->node->parent != NULL);
1902 if (item == folder->trash || item == special_trash
1903 || folder_has_parent_of_type(item, F_TRASH)) {
1904 GSList *msglist = folder_item_get_msg_list(item);
1905 SET_SENS("/Empty trash...", msglist != NULL);
1906 procmsg_msg_list_free(msglist);
1908 if (item == folder->queue || item == special_queue
1909 || folder_has_parent_of_type(item, F_QUEUE)) {
1910 GSList *msglist = folder_item_get_msg_list(item);
1911 SET_SENS("/Send queue...", msglist != NULL);
1912 procmsg_msg_list_free(msglist);
1916 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1917 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1918 event->button, event->time);
1923 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1924 FolderView *folderview)
1926 GtkCList *clist = GTK_CLIST(ctree);
1927 gint prev_row = -1, row = -1, column = -1;
1929 if (!event) return FALSE;
1931 if (event->button == 1 || event->button == 2) {
1932 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1933 folderview->open_folder = TRUE;
1935 if (event->type == GDK_2BUTTON_PRESS) {
1936 if (clist->selection) {
1939 node = GTK_CTREE_NODE(clist->selection->data);
1941 gtk_ctree_toggle_expansion(
1944 folderview->open_folder = FALSE;
1951 if (event->button == 2 || event->button == 3) {
1953 if (clist->selection) {
1956 node = GTK_CTREE_NODE(clist->selection->data);
1958 prev_row = gtkut_ctree_get_nth_from_node
1959 (GTK_CTREE(ctree), node);
1962 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1965 if (prev_row != row) {
1966 gtk_clist_unselect_all(clist);
1967 if (event->button == 2)
1968 folderview_select_node
1970 gtk_ctree_node_nth(GTK_CTREE(ctree),
1973 gtk_clist_select_row(clist, row, column);
1977 if (event->button != 3) return FALSE;
1979 folderview_set_sens_and_popup_menu(folderview, row, event);
1983 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1984 FolderView *folderview)
1986 if (!event) return FALSE;
1988 if (event->button == 1 && folderview->open_folder == FALSE &&
1989 folderview->opened != NULL) {
1990 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1991 folderview->opened);
1992 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1998 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1999 FolderView *folderview)
2001 if (!event) return FALSE;
2003 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
2006 switch (event->keyval) {
2008 if (folderview->selected) {
2009 folderview_select_node(folderview,
2010 folderview->selected);
2014 if (folderview->selected) {
2015 if (folderview->opened == folderview->selected &&
2016 (!folderview->summaryview->folder_item ||
2017 folderview->summaryview->folder_item->total_msgs == 0))
2018 folderview_select_next_unread(folderview, TRUE);
2020 folderview_select_node(folderview,
2021 folderview->selected);
2031 typedef struct _PostponedSelectData
2036 FolderView *folderview;
2037 } PostponedSelectData;
2039 static gboolean postpone_select(void *data)
2041 PostponedSelectData *psdata = (PostponedSelectData *)data;
2042 debug_print("trying again\n");
2043 psdata->folderview->open_folder = TRUE;
2044 main_window_cursor_normal(psdata->folderview->mainwin);
2045 STATUSBAR_POP(psdata->folderview->mainwin);
2046 folderview_selected(psdata->ctree, psdata->row,
2047 psdata->column, psdata->folderview);
2052 void folderview_close_opened(FolderView *folderview)
2054 if (folderview->opened) {
2055 FolderItem *olditem;
2057 olditem = gtk_ctree_node_get_row_data(folderview->ctree, folderview->opened);
2059 gchar *buf = g_strdup_printf(_("Closing Folder %s..."),
2060 olditem->path ? olditem->path:olditem->name);
2061 /* will be null if we just moved the previously opened folder */
2062 STATUSBAR_PUSH(folderview->mainwin, buf);
2063 main_window_cursor_wait(folderview->mainwin);
2065 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2066 summary_show(folderview->summaryview, NULL);
2067 folder_item_close(olditem);
2068 main_window_cursor_normal(folderview->mainwin);
2069 STATUSBAR_POP(folderview->mainwin);
2073 if (folderview->opened &&
2074 !GTK_CTREE_ROW(folderview->opened)->children)
2075 gtk_ctree_collapse(folderview->ctree, folderview->opened);
2077 folderview->opened = NULL;
2079 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2080 gint column, FolderView *folderview)
2082 static gboolean can_select = TRUE; /* exclusive lock */
2087 GtkCTreeNode *old_opened = folderview->opened;
2089 folderview->selected = row;
2091 debug_print("newly selected %p, opened %p\n", folderview->selected,
2092 folderview->opened);
2093 if (folderview->opened == row) {
2094 folderview->open_folder = FALSE;
2099 if (!can_select || summary_is_locked(folderview->summaryview)) {
2100 if (folderview->opened) {
2101 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2102 gtk_ctree_select(ctree, folderview->opened);
2104 folderview->open_folder = FALSE;
2109 if (!folderview->open_folder) {
2113 item = gtk_ctree_node_get_row_data(ctree, row);
2114 if (!item || item->no_select) {
2116 folderview->open_folder = FALSE;
2122 /* Save cache for old folder */
2123 /* We don't want to lose all caches if sylpheed crashed */
2124 /* resets folderview->opened to NULL */
2125 folderview_close_opened(folderview);
2127 /* CLAWS: set compose button type: news folder items
2128 * always have a news folder as parent */
2130 toolbar_set_compose_button
2131 (folderview->mainwin->toolbar,
2132 FOLDER_TYPE(item->folder) == F_NEWS ?
2133 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2136 debug_print("Folder %s is selected\n", item->path);
2138 if (!GTK_CTREE_ROW(row)->children)
2139 gtk_ctree_expand(ctree, row);
2141 /* ungrab the mouse event */
2142 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2143 gtk_grab_remove(GTK_WIDGET(ctree));
2144 if (gdk_pointer_is_grabbed())
2145 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2149 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2150 item->path : "(null)");
2151 debug_print("%s\n", buf);
2152 STATUSBAR_PUSH(folderview->mainwin, buf);
2155 main_window_cursor_wait(folderview->mainwin);
2157 res = folder_item_open(item);
2159 main_window_cursor_normal(folderview->mainwin);
2160 STATUSBAR_POP(folderview->mainwin);
2162 alertpanel_error(_("Folder could not be opened."));
2164 folderview->open_folder = FALSE;
2168 } else if (res == -2) {
2169 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2170 data->ctree = ctree;
2172 data->column = column;
2173 data->folderview = folderview;
2174 debug_print("postponing open of %s till end of scan\n",
2175 item->path ? item->path:item->name);
2176 folderview->open_folder = FALSE;
2178 g_timeout_add(500, postpone_select, data);
2183 main_window_cursor_normal(folderview->mainwin);
2186 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2187 opened = summary_show(folderview->summaryview, item);
2189 folder_clean_cache_memory(item);
2192 gtkut_ctree_set_focus_row(ctree, old_opened);
2193 gtk_ctree_select(ctree, old_opened);
2194 folderview->opened = old_opened;
2196 folderview->opened = row;
2197 if (gtk_ctree_node_is_visible(ctree, row)
2198 != GTK_VISIBILITY_FULL)
2199 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2202 STATUSBAR_POP(folderview->mainwin);
2204 folderview->open_folder = FALSE;
2209 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2210 FolderView *folderview)
2214 item = gtk_ctree_node_get_row_data(ctree, node);
2215 g_return_if_fail(item != NULL);
2216 item->collapsed = FALSE;
2217 folderview_update_node(folderview, node);
2220 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2221 FolderView *folderview)
2225 item = gtk_ctree_node_get_row_data(ctree, node);
2226 g_return_if_fail(item != NULL);
2227 item->collapsed = TRUE;
2228 folderview_update_node(folderview, node);
2231 static void folderview_popup_close(GtkMenuShell *menu_shell,
2232 FolderView *folderview)
2234 if (!folderview->opened) return;
2236 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2239 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2240 FolderView *folderview)
2242 FolderColumnType type = folderview->col_state[column].type;
2244 prefs_common.folder_col_size[type] = width;
2247 static void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2251 folderview_create_folder_node(folderview, item);
2253 if (!item || !item->folder || !item->folder->node)
2256 srcnode = item->folder->node;
2257 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2258 srcnode = srcnode->children;
2259 while (srcnode != NULL) {
2260 if (srcnode && srcnode->data) {
2261 FolderItem *next_item = (FolderItem*) srcnode->data;
2262 folderview_create_folder_node_recursive(folderview, next_item);
2264 srcnode = srcnode->next;
2268 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2270 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2271 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2272 GtkCTreeNode *node, *parent_node;
2273 gint *col_pos = folderview->col_pos;
2274 FolderItemUpdateData hookdata;
2276 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2277 if (parent_node == NULL)
2280 gtk_clist_freeze(GTK_CLIST(ctree));
2282 text[col_pos[F_COL_FOLDER]] = item->name;
2283 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2285 folderxpm, folderxpmmask,
2286 folderopenxpm, folderopenxpmmask,
2288 gtk_ctree_expand(ctree, parent_node);
2289 gtk_ctree_node_set_row_data(ctree, node, item);
2291 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2292 folderview_sort_folders(folderview, parent_node, item->folder);
2294 hookdata.item = item;
2295 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2296 hookdata.msg = NULL;
2297 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2299 gtk_clist_thaw(GTK_CLIST(ctree));
2302 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2305 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2307 GSList *mlist = NULL;
2309 FolderItem *special_trash = NULL;
2312 if (!folderview->selected) return;
2313 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2314 g_return_if_fail(item != NULL);
2315 g_return_if_fail(item->folder != NULL);
2317 if (NULL != (ac = account_find_from_item(item)))
2318 special_trash = account_get_special_folder(ac, F_TRASH);
2320 if (item != item->folder->trash && item != special_trash
2321 && !folder_has_parent_of_type(item, F_TRASH)) return;
2323 if (prefs_common.ask_on_clean) {
2324 if (alertpanel(_("Empty trash"),
2325 _("Delete all messages in trash?"),
2326 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2330 mlist = folder_item_get_msg_list(item);
2332 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2333 MsgInfo * msginfo = (MsgInfo *) cur->data;
2334 if (MSG_IS_LOCKED(msginfo->flags))
2336 /* is it partially received? (partial_recv isn't cached) */
2337 if (msginfo->total_size != 0 &&
2338 msginfo->size != (off_t)msginfo->total_size)
2339 partial_mark_for_delete(msginfo);
2341 procmsg_msg_list_free(mlist);
2343 folder_item_remove_all_msg(item);
2346 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2349 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2351 FolderItem *special_queue = NULL;
2353 gchar *errstr = NULL;
2355 if (!folderview->selected) return;
2356 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2357 g_return_if_fail(item != NULL);
2358 g_return_if_fail(item->folder != NULL);
2360 if (NULL != (ac = account_find_from_item(item)))
2361 special_queue = account_get_special_folder(ac, F_QUEUE);
2363 if (item != item->folder->queue && item != special_queue
2364 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2366 if (procmsg_queue_is_empty(item))
2369 if (prefs_common.work_offline)
2370 if (alertpanel(_("Offline warning"),
2371 _("You're working offline. Override?"),
2372 GTK_STOCK_NO, GTK_STOCK_YES,
2373 NULL) != G_ALERTALTERNATE)
2376 /* ask for confirmation before sending queued messages only
2377 in online mode and if there is at least one message queued
2378 in any of the folder queue
2380 if (prefs_common.confirm_send_queued_messages) {
2381 if (!prefs_common.work_offline) {
2382 if (alertpanel(_("Send queued messages"),
2383 _("Send all queued messages?"),
2384 GTK_STOCK_CANCEL, _("_Send"),
2385 NULL) != G_ALERTALTERNATE)
2390 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2392 alertpanel_error_log(_("Some errors occurred while "
2393 "sending queued messages."));
2395 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2396 "while sending queued messages:\n%s"), errstr);
2398 alertpanel_error_log(tmp);
2404 static void folderview_search_cb(FolderView *folderview, guint action,
2407 summary_search(folderview->summaryview);
2410 static void folderview_property_cb(FolderView *folderview, guint action,
2413 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2416 if (!folderview->selected) return;
2418 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2419 g_return_if_fail(item != NULL);
2420 g_return_if_fail(item->folder != NULL);
2422 prefs_folder_item_open(item);
2425 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2427 GSList *list = NULL;
2428 GSList *done = NULL;
2429 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2431 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2432 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2433 && list->data != node) {
2434 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2435 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2438 for (list = done; list != NULL; list = g_slist_next(list)) {
2439 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2445 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2446 FolderItem *to_folder, gboolean copy)
2448 FolderItem *from_parent = NULL;
2449 FolderItem *new_folder = NULL;
2450 GtkCTreeNode *src_node = NULL;
2454 g_return_if_fail(folderview != NULL);
2455 g_return_if_fail(from_folder != NULL);
2456 g_return_if_fail(to_folder != NULL);
2458 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2459 from_parent = folder_item_parent(from_folder);
2461 if (prefs_common.warn_dnd) {
2462 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2463 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2464 from_folder->name, to_folder->name);
2465 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2466 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2467 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2470 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2472 else if (status & G_ALERTDISABLE)
2473 prefs_common.warn_dnd = FALSE;
2476 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2477 from_folder->name, to_folder->name);
2478 STATUSBAR_PUSH(folderview->mainwin, buf);
2480 summary_clear_all(folderview->summaryview);
2481 folderview->opened = NULL;
2482 folderview->selected = NULL;
2483 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2485 main_window_cursor_wait(folderview->mainwin);
2487 statusbar_verbosity_set(FALSE);
2488 folder_item_update_freeze();
2489 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2490 statusbar_verbosity_set(FALSE);
2491 main_window_cursor_normal(folderview->mainwin);
2492 STATUSBAR_POP(folderview->mainwin);
2493 folder_item_update_thaw();
2494 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2496 folderview_sort_folders(folderview,
2497 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2498 NULL, to_folder), new_folder->folder);
2499 folderview_select(folderview, new_folder);
2501 statusbar_verbosity_set(FALSE);
2502 main_window_cursor_normal(folderview->mainwin);
2503 STATUSBAR_POP(folderview->mainwin);
2504 folder_item_update_thaw();
2506 case F_MOVE_FAILED_DEST_IS_PARENT:
2507 alertpanel_error(_("Source and destination are the same."));
2509 case F_MOVE_FAILED_DEST_IS_CHILD:
2510 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2511 _("Can't move a folder to one of its children."));
2513 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2514 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2517 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2522 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2525 static gint folderview_clist_compare(GtkCList *clist,
2526 gconstpointer ptr1, gconstpointer ptr2)
2528 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2529 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2531 if (item1->order > 0 && item2->order > 0) // if we have an order item, use it
2533 return item1->order - item2->order;
2536 // if only one folder has an order it comes first
2537 if (item1->order > 0)
2541 if (item2->order > 0)
2547 return (item2->name != NULL);
2551 return g_utf8_collate(item1->name, item2->name);
2554 static void folderview_processing_cb(FolderView *folderview, guint action,
2557 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2561 if (!folderview->selected) return;
2563 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2564 g_return_if_fail(item != NULL);
2565 g_return_if_fail(item->folder != NULL);
2567 id = folder_item_get_identifier(item);
2568 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2571 prefs_filtering_open(&item->prefs->processing, title,
2572 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2576 void folderview_set_target_folder_color(gint color_op)
2580 FolderView *folderview;
2582 for (list = folderview_list; list != NULL; list = list->next) {
2583 folderview = (FolderView *)list->data;
2584 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2586 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2587 folderview->color_op;
2593 static gchar *last_font = NULL;
2594 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2602 void folderview_reflect_prefs(void)
2604 gboolean update_font = TRUE;
2605 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2606 FolderItem *item = folderview_get_selected_item(folderview);
2607 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2608 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2609 gint height = pos->value;
2611 if (last_font && !strcmp(last_font, NORMAL_FONT))
2612 update_font = FALSE;
2615 last_font = g_strdup(NORMAL_FONT);
2618 normal_style = normal_color_style = bold_style =
2619 bold_color_style = bold_tgtfold_style = NULL;
2621 folderview_init(folderview);
2623 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2624 folderview_column_set_titles(folderview);
2625 folderview_set_all();
2627 g_signal_handlers_block_by_func
2628 (G_OBJECT(folderview->ctree),
2629 G_CALLBACK(folderview_selected), folderview);
2632 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2633 GTK_CTREE(folderview->ctree), NULL, item);
2635 folderview_select(folderview, item);
2636 folderview->open_folder = FALSE;
2637 folderview->selected = node;
2640 g_signal_handlers_unblock_by_func
2641 (G_OBJECT(folderview->ctree),
2642 G_CALLBACK(folderview_selected), folderview);
2644 pos = gtk_scrolled_window_get_vadjustment(
2645 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2646 gtk_adjustment_set_value(pos, height);
2647 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2650 static void drag_state_stop(FolderView *folderview)
2652 if (folderview->drag_timer)
2653 g_source_remove(folderview->drag_timer);
2654 folderview->drag_timer = 0;
2655 folderview->drag_node = NULL;
2658 static gint folderview_defer_expand(FolderView *folderview)
2660 if (folderview->drag_node) {
2661 folderview_recollapse_nodes(folderview, folderview->drag_node);
2662 if (folderview->drag_item->collapsed) {
2663 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2664 folderview->nodes_to_recollapse = g_slist_append
2665 (folderview->nodes_to_recollapse, folderview->drag_node);
2668 folderview->drag_item = NULL;
2669 folderview->drag_timer = 0;
2673 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2675 /* the idea is that we call drag_state_start() whenever we want expansion to
2676 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2677 * we need to call drag_state_stop() */
2678 drag_state_stop(folderview);
2679 /* request expansion */
2680 if (0 != (folderview->drag_timer = g_timeout_add
2681 (prefs_common.hover_timeout,
2682 (GtkFunction)folderview_defer_expand,
2684 folderview->drag_node = node;
2685 folderview->drag_item = item;
2689 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2690 FolderView *folderview)
2692 GdkDragContext *context;
2694 g_return_if_fail(folderview != NULL);
2695 if (folderview->selected == NULL) return;
2696 if (folderview->nodes_to_recollapse)
2697 g_slist_free(folderview->nodes_to_recollapse);
2698 folderview->nodes_to_recollapse = NULL;
2699 context = gtk_drag_begin(widget, folderview->target_list,
2700 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2701 gtk_drag_set_icon_default(context);
2704 static void folderview_drag_data_get(GtkWidget *widget,
2705 GdkDragContext *drag_context,
2706 GtkSelectionData *selection_data,
2709 FolderView *folderview)
2713 gchar *source = NULL;
2714 if (info == TARGET_DUMMY) {
2715 for (cur = GTK_CLIST(folderview->ctree)->selection;
2716 cur != NULL; cur = cur->next) {
2717 item = gtk_ctree_node_get_row_data
2718 (GTK_CTREE(folderview->ctree),
2719 GTK_CTREE_NODE(cur->data));
2721 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2722 gtk_selection_data_set(selection_data,
2723 selection_data->target, 8,
2724 source, strlen(source));
2730 g_warning("unknown info %d\n", info);
2734 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2736 FolderUpdateData *hookdata;
2737 FolderView *folderview;
2741 folderview = (FolderView *) userdata;
2742 g_return_val_if_fail(hookdata != NULL, FALSE);
2743 g_return_val_if_fail(folderview != NULL, FALSE);
2745 ctree = folderview->ctree;
2746 g_return_val_if_fail(ctree != NULL, FALSE);
2748 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2749 folderview_create_folder_node(folderview, hookdata->item);
2750 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2751 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2752 NULL, folder_item_parent(hookdata->item));
2753 folderview_sort_folders(folderview, node, hookdata->folder);
2754 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2757 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2759 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2760 if (folderview->selected == node)
2761 folderview->selected = NULL;
2762 if (folderview->opened == node)
2763 folderview->opened = NULL;
2765 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2766 folderview_set(folderview);
2771 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2772 GdkDragContext *context,
2776 FolderView *folderview)
2779 FolderItem *item = NULL, *src_item = NULL;
2780 GtkCTreeNode *node = NULL;
2781 gboolean acceptable = FALSE;
2782 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2783 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2784 int height = (int)pos->page_size;
2785 int total_height = (int)pos->upper;
2786 int vpos = (int) pos->value;
2788 if (gtk_clist_get_selection_info
2789 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2790 GtkWidget *srcwidget;
2792 if (y > height - 24 && height + vpos < total_height)
2793 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2795 if (y < 48 && y > 0)
2796 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2798 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2799 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2800 src_item = folderview->summaryview->folder_item;
2802 srcwidget = gtk_drag_get_source_widget(context);
2803 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2804 /* comes from summaryview */
2805 /* we are copying messages, so only accept folder items that are not
2806 the source item, are no root items and can copy messages */
2807 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2808 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2809 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2811 } else if (srcwidget == folderview->ctree) {
2812 /* comes from folderview */
2813 /* we are moving folder items, only accept folders that are not
2814 the source items and can copy messages and create folder items */
2815 if (item && item->folder && src_item && src_item != item &&
2816 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2817 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2818 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2819 || item->folder == src_item->folder))
2822 /* comes from another app */
2823 /* we are adding messages, so only accept folder items that are
2824 no root items and can copy messages */
2825 if (item && item->folder && folder_item_parent(item) != NULL
2826 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2827 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2832 if (acceptable || (src_item && src_item == item))
2833 drag_state_start(folderview, node, item);
2836 g_signal_handlers_block_by_func
2838 G_CALLBACK(folderview_selected), folderview);
2839 gtk_ctree_select(GTK_CTREE(widget), node);
2840 g_signal_handlers_unblock_by_func
2842 G_CALLBACK(folderview_selected), folderview);
2843 gdk_drag_status(context,
2844 (context->actions == GDK_ACTION_COPY ?
2845 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2847 if (folderview->opened)
2848 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2849 gdk_drag_status(context, 0, time);
2855 static void folderview_drag_leave_cb(GtkWidget *widget,
2856 GdkDragContext *context,
2858 FolderView *folderview)
2860 drag_state_stop(folderview);
2861 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2864 static void free_info (gpointer stuff, gpointer data)
2869 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2870 guint time, FolderItem *item)
2873 GSList *msglist = NULL;
2874 list = uri_list_extract_filenames(data);
2875 if (!(item && item->folder && folder_item_parent(item) != NULL
2876 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2878 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2879 debug_print("item doesn't fit\n");
2883 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2884 debug_print("list is empty\n");
2887 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2888 MsgFileInfo *info = NULL;
2890 if (file_is_email((gchar *)tmp->data)) {
2891 info = g_new0(MsgFileInfo, 1);
2892 info->msginfo = NULL;
2893 info->file = (gchar *)tmp->data;
2894 msglist = g_slist_prepend(msglist, info);
2895 debug_print("file is a mail\n");
2897 debug_print("file isn't a mail\n");
2901 msglist = g_slist_reverse(msglist);
2902 folder_item_add_msgs(item, msglist, FALSE);
2903 g_slist_foreach(msglist, free_info, NULL);
2904 g_slist_free(msglist);
2905 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2907 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2909 list_free_strings(list);
2913 static void folderview_drag_received_cb(GtkWidget *widget,
2914 GdkDragContext *drag_context,
2917 GtkSelectionData *data,
2920 FolderView *folderview)
2923 FolderItem *item = NULL, *src_item;
2926 if (info == TARGET_DUMMY) {
2927 drag_state_stop(folderview);
2928 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2929 /* comes from summaryview */
2930 if (gtk_clist_get_selection_info
2931 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2934 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2935 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2936 src_item = folderview->summaryview->folder_item;
2938 /* re-check (due to acceptable possibly set for folder moves */
2939 if (!(item && item->folder && item->path && !item->no_select &&
2940 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2943 if (item && src_item) {
2944 switch (drag_context->action) {
2945 case GDK_ACTION_COPY:
2946 summary_copy_selected_to(folderview->summaryview, item);
2947 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2949 case GDK_ACTION_MOVE:
2950 case GDK_ACTION_DEFAULT:
2952 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2953 summary_copy_selected_to(folderview->summaryview, item);
2955 summary_move_selected_to(folderview->summaryview, item);
2956 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2959 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2961 /* comes from folderview */
2963 gboolean folder_is_normal = TRUE;
2964 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2966 source = data->data + 17;
2967 if (gtk_clist_get_selection_info
2968 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2970 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2973 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2974 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2975 src_item = folder_find_item_from_identifier(source);
2979 src_item->stype == F_NORMAL &&
2980 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2981 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2982 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2983 !folder_has_parent_of_type(src_item, F_TRASH);
2984 if (!item || item->no_select || !src_item
2985 || !folder_is_normal) {
2986 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2990 folderview_move_folder(folderview, src_item, item, copy);
2991 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2993 folderview->nodes_to_recollapse = NULL;
2994 } else if (info == TARGET_MAIL_URI_LIST) {
2995 if (gtk_clist_get_selection_info
2996 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2999 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
3001 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3002 debug_print("no node\n");
3005 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
3007 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3008 debug_print("no item\n");
3011 folderview_finish_dnd(data->data, drag_context, time, item);
3015 static void folderview_drag_end_cb(GtkWidget *widget,
3016 GdkDragContext *drag_context,
3017 FolderView *folderview)
3019 drag_state_stop(folderview);
3020 g_slist_free(folderview->nodes_to_recollapse);
3021 folderview->nodes_to_recollapse = NULL;
3024 void folderview_register_popup(FolderViewPopup *fpopup)
3028 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3029 FolderView *folderview = folderviews->data;
3030 GtkItemFactory *factory;
3032 factory = create_ifactory(folderview, fpopup);
3033 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
3035 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
3038 void folderview_unregister_popup(FolderViewPopup *fpopup)
3042 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3043 FolderView *folderview = folderviews->data;
3045 g_hash_table_remove(folderview->popups, fpopup->klass);
3047 g_hash_table_remove(folderview_popups, fpopup->klass);