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) {
2011 if (folderview->selected) {
2012 folderview_select_node(folderview,
2013 folderview->selected);
2018 if (folderview->selected && GTK_CTREE_ROW(folderview->selected)->children) {
2019 gtk_ctree_toggle_expansion(
2020 GTK_CTREE(folderview->ctree),
2021 folderview->selected);
2026 if (folderview->selected) {
2027 if (folderview->opened == folderview->selected &&
2028 (!folderview->summaryview->folder_item ||
2029 folderview->summaryview->folder_item->total_msgs == 0))
2030 folderview_select_next_unread(folderview, TRUE);
2032 folderview_select_node(folderview,
2033 folderview->selected);
2043 typedef struct _PostponedSelectData
2048 FolderView *folderview;
2049 } PostponedSelectData;
2051 static gboolean postpone_select(void *data)
2053 PostponedSelectData *psdata = (PostponedSelectData *)data;
2054 debug_print("trying again\n");
2055 psdata->folderview->open_folder = TRUE;
2056 main_window_cursor_normal(psdata->folderview->mainwin);
2057 STATUSBAR_POP(psdata->folderview->mainwin);
2058 folderview_selected(psdata->ctree, psdata->row,
2059 psdata->column, psdata->folderview);
2064 void folderview_close_opened(FolderView *folderview)
2066 if (folderview->opened) {
2067 FolderItem *olditem;
2069 olditem = gtk_ctree_node_get_row_data(folderview->ctree, folderview->opened);
2071 gchar *buf = g_strdup_printf(_("Closing Folder %s..."),
2072 olditem->path ? olditem->path:olditem->name);
2073 /* will be null if we just moved the previously opened folder */
2074 STATUSBAR_PUSH(folderview->mainwin, buf);
2075 main_window_cursor_wait(folderview->mainwin);
2077 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2078 summary_show(folderview->summaryview, NULL);
2079 folder_item_close(olditem);
2080 main_window_cursor_normal(folderview->mainwin);
2081 STATUSBAR_POP(folderview->mainwin);
2085 if (folderview->opened &&
2086 !GTK_CTREE_ROW(folderview->opened)->children)
2087 gtk_ctree_collapse(folderview->ctree, folderview->opened);
2089 folderview->opened = NULL;
2091 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2092 gint column, FolderView *folderview)
2094 static gboolean can_select = TRUE; /* exclusive lock */
2099 GtkCTreeNode *old_opened = folderview->opened;
2101 folderview->selected = row;
2103 debug_print("newly selected %p, opened %p\n", folderview->selected,
2104 folderview->opened);
2105 if (folderview->opened == row) {
2106 folderview->open_folder = FALSE;
2111 if (!can_select || summary_is_locked(folderview->summaryview)) {
2112 if (folderview->opened) {
2113 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2114 gtk_ctree_select(ctree, folderview->opened);
2116 folderview->open_folder = FALSE;
2121 if (!folderview->open_folder) {
2125 item = gtk_ctree_node_get_row_data(ctree, row);
2126 if (!item || item->no_select) {
2128 folderview->open_folder = FALSE;
2134 /* Save cache for old folder */
2135 /* We don't want to lose all caches if sylpheed crashed */
2136 /* resets folderview->opened to NULL */
2137 folderview_close_opened(folderview);
2139 /* CLAWS: set compose button type: news folder items
2140 * always have a news folder as parent */
2142 toolbar_set_compose_button
2143 (folderview->mainwin->toolbar,
2144 FOLDER_TYPE(item->folder) == F_NEWS ?
2145 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2148 debug_print("Folder %s is selected\n", item->path);
2150 if (!GTK_CTREE_ROW(row)->children)
2151 gtk_ctree_expand(ctree, row);
2153 /* ungrab the mouse event */
2154 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2155 gtk_grab_remove(GTK_WIDGET(ctree));
2156 if (gdk_pointer_is_grabbed())
2157 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2161 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2162 item->path : "(null)");
2163 debug_print("%s\n", buf);
2164 STATUSBAR_PUSH(folderview->mainwin, buf);
2167 main_window_cursor_wait(folderview->mainwin);
2169 res = folder_item_open(item);
2171 main_window_cursor_normal(folderview->mainwin);
2172 STATUSBAR_POP(folderview->mainwin);
2174 alertpanel_error(_("Folder could not be opened."));
2176 folderview->open_folder = FALSE;
2180 } else if (res == -2) {
2181 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2182 data->ctree = ctree;
2184 data->column = column;
2185 data->folderview = folderview;
2186 debug_print("postponing open of %s till end of scan\n",
2187 item->path ? item->path:item->name);
2188 folderview->open_folder = FALSE;
2190 g_timeout_add(500, postpone_select, data);
2195 main_window_cursor_normal(folderview->mainwin);
2198 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2199 opened = summary_show(folderview->summaryview, item);
2201 folder_clean_cache_memory(item);
2204 gtkut_ctree_set_focus_row(ctree, old_opened);
2205 gtk_ctree_select(ctree, old_opened);
2206 folderview->opened = old_opened;
2208 folderview->opened = row;
2209 if (gtk_ctree_node_is_visible(ctree, row)
2210 != GTK_VISIBILITY_FULL)
2211 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2214 STATUSBAR_POP(folderview->mainwin);
2216 folderview->open_folder = FALSE;
2221 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2222 FolderView *folderview)
2226 item = gtk_ctree_node_get_row_data(ctree, node);
2227 g_return_if_fail(item != NULL);
2228 item->collapsed = FALSE;
2229 folderview_update_node(folderview, node);
2232 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2233 FolderView *folderview)
2237 item = gtk_ctree_node_get_row_data(ctree, node);
2238 g_return_if_fail(item != NULL);
2239 item->collapsed = TRUE;
2240 folderview_update_node(folderview, node);
2243 static void folderview_popup_close(GtkMenuShell *menu_shell,
2244 FolderView *folderview)
2246 if (!folderview->opened) return;
2248 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2251 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2252 FolderView *folderview)
2254 FolderColumnType type = folderview->col_state[column].type;
2256 prefs_common.folder_col_size[type] = width;
2259 static void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2263 folderview_create_folder_node(folderview, item);
2265 if (!item || !item->folder || !item->folder->node)
2268 srcnode = item->folder->node;
2269 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2270 srcnode = srcnode->children;
2271 while (srcnode != NULL) {
2272 if (srcnode && srcnode->data) {
2273 FolderItem *next_item = (FolderItem*) srcnode->data;
2274 folderview_create_folder_node_recursive(folderview, next_item);
2276 srcnode = srcnode->next;
2280 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2282 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2283 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2284 GtkCTreeNode *node, *parent_node;
2285 gint *col_pos = folderview->col_pos;
2286 FolderItemUpdateData hookdata;
2288 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2289 if (parent_node == NULL)
2292 gtk_clist_freeze(GTK_CLIST(ctree));
2294 text[col_pos[F_COL_FOLDER]] = item->name;
2295 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2297 folderxpm, folderxpmmask,
2298 folderopenxpm, folderopenxpmmask,
2300 gtk_ctree_expand(ctree, parent_node);
2301 gtk_ctree_node_set_row_data(ctree, node, item);
2303 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2304 folderview_sort_folders(folderview, parent_node, item->folder);
2306 hookdata.item = item;
2307 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2308 hookdata.msg = NULL;
2309 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2311 gtk_clist_thaw(GTK_CLIST(ctree));
2314 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2317 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2319 GSList *mlist = NULL;
2321 FolderItem *special_trash = NULL;
2324 if (!folderview->selected) return;
2325 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2326 g_return_if_fail(item != NULL);
2327 g_return_if_fail(item->folder != NULL);
2329 if (NULL != (ac = account_find_from_item(item)))
2330 special_trash = account_get_special_folder(ac, F_TRASH);
2332 if (item != item->folder->trash && item != special_trash
2333 && !folder_has_parent_of_type(item, F_TRASH)) return;
2335 if (prefs_common.ask_on_clean) {
2336 if (alertpanel(_("Empty trash"),
2337 _("Delete all messages in trash?"),
2338 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2342 mlist = folder_item_get_msg_list(item);
2344 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2345 MsgInfo * msginfo = (MsgInfo *) cur->data;
2346 if (MSG_IS_LOCKED(msginfo->flags))
2348 /* is it partially received? (partial_recv isn't cached) */
2349 if (msginfo->total_size != 0 &&
2350 msginfo->size != (off_t)msginfo->total_size)
2351 partial_mark_for_delete(msginfo);
2353 procmsg_msg_list_free(mlist);
2355 folder_item_remove_all_msg(item);
2358 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2361 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2363 FolderItem *special_queue = NULL;
2365 gchar *errstr = NULL;
2367 if (!folderview->selected) return;
2368 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2369 g_return_if_fail(item != NULL);
2370 g_return_if_fail(item->folder != NULL);
2372 if (NULL != (ac = account_find_from_item(item)))
2373 special_queue = account_get_special_folder(ac, F_QUEUE);
2375 if (item != item->folder->queue && item != special_queue
2376 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2378 if (procmsg_queue_is_empty(item))
2381 if (prefs_common.work_offline)
2382 if (alertpanel(_("Offline warning"),
2383 _("You're working offline. Override?"),
2384 GTK_STOCK_NO, GTK_STOCK_YES,
2385 NULL) != G_ALERTALTERNATE)
2388 /* ask for confirmation before sending queued messages only
2389 in online mode and if there is at least one message queued
2390 in any of the folder queue
2392 if (prefs_common.confirm_send_queued_messages) {
2393 if (!prefs_common.work_offline) {
2394 if (alertpanel(_("Send queued messages"),
2395 _("Send all queued messages?"),
2396 GTK_STOCK_CANCEL, _("_Send"),
2397 NULL) != G_ALERTALTERNATE)
2402 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2404 alertpanel_error_log(_("Some errors occurred while "
2405 "sending queued messages."));
2407 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2408 "while sending queued messages:\n%s"), errstr);
2410 alertpanel_error_log(tmp);
2416 static void folderview_search_cb(FolderView *folderview, guint action,
2419 summary_search(folderview->summaryview);
2422 static void folderview_property_cb(FolderView *folderview, guint action,
2425 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2428 if (!folderview->selected) return;
2430 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2431 g_return_if_fail(item != NULL);
2432 g_return_if_fail(item->folder != NULL);
2434 prefs_folder_item_open(item);
2437 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2439 GSList *list = NULL;
2440 GSList *done = NULL;
2441 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2443 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2444 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2445 && list->data != node) {
2446 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2447 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2450 for (list = done; list != NULL; list = g_slist_next(list)) {
2451 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2457 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2458 FolderItem *to_folder, gboolean copy)
2460 FolderItem *from_parent = NULL;
2461 FolderItem *new_folder = NULL;
2462 GtkCTreeNode *src_node = NULL;
2466 g_return_if_fail(folderview != NULL);
2467 g_return_if_fail(from_folder != NULL);
2468 g_return_if_fail(to_folder != NULL);
2470 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2471 from_parent = folder_item_parent(from_folder);
2473 if (prefs_common.warn_dnd) {
2474 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2475 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2476 from_folder->name, to_folder->name);
2477 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2478 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2479 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2482 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2484 else if (status & G_ALERTDISABLE)
2485 prefs_common.warn_dnd = FALSE;
2488 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2489 from_folder->name, to_folder->name);
2490 STATUSBAR_PUSH(folderview->mainwin, buf);
2492 summary_clear_all(folderview->summaryview);
2493 folderview->opened = NULL;
2494 folderview->selected = NULL;
2495 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2497 main_window_cursor_wait(folderview->mainwin);
2499 statusbar_verbosity_set(FALSE);
2500 folder_item_update_freeze();
2501 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2502 statusbar_verbosity_set(FALSE);
2503 main_window_cursor_normal(folderview->mainwin);
2504 STATUSBAR_POP(folderview->mainwin);
2505 folder_item_update_thaw();
2506 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2508 folderview_sort_folders(folderview,
2509 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2510 NULL, to_folder), new_folder->folder);
2511 folderview_select(folderview, new_folder);
2513 statusbar_verbosity_set(FALSE);
2514 main_window_cursor_normal(folderview->mainwin);
2515 STATUSBAR_POP(folderview->mainwin);
2516 folder_item_update_thaw();
2518 case F_MOVE_FAILED_DEST_IS_PARENT:
2519 alertpanel_error(_("Source and destination are the same."));
2521 case F_MOVE_FAILED_DEST_IS_CHILD:
2522 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2523 _("Can't move a folder to one of its children."));
2525 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2526 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2529 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2534 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2537 static gint folderview_clist_compare(GtkCList *clist,
2538 gconstpointer ptr1, gconstpointer ptr2)
2540 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2541 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2543 if (item1->order > 0 && item2->order > 0) // if we have an order item, use it
2545 return item1->order - item2->order;
2548 // if only one folder has an order it comes first
2549 if (item1->order > 0)
2553 if (item2->order > 0)
2559 return (item2->name != NULL);
2563 return g_utf8_collate(item1->name, item2->name);
2566 static void folderview_processing_cb(FolderView *folderview, guint action,
2569 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2573 if (!folderview->selected) return;
2575 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2576 g_return_if_fail(item != NULL);
2577 g_return_if_fail(item->folder != NULL);
2579 id = folder_item_get_identifier(item);
2580 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2583 prefs_filtering_open(&item->prefs->processing, title,
2584 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2588 void folderview_set_target_folder_color(gint color_op)
2592 FolderView *folderview;
2594 for (list = folderview_list; list != NULL; list = list->next) {
2595 folderview = (FolderView *)list->data;
2596 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2598 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2599 folderview->color_op;
2605 static gchar *last_font = NULL;
2606 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2614 void folderview_reflect_prefs(void)
2616 gboolean update_font = TRUE;
2617 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2618 FolderItem *item = folderview_get_selected_item(folderview);
2619 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2620 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2621 gint height = pos->value;
2623 if (last_font && !strcmp(last_font, NORMAL_FONT))
2624 update_font = FALSE;
2627 last_font = g_strdup(NORMAL_FONT);
2630 normal_style = normal_color_style = bold_style =
2631 bold_color_style = bold_tgtfold_style = NULL;
2633 folderview_init(folderview);
2635 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2636 folderview_column_set_titles(folderview);
2637 folderview_set_all();
2639 g_signal_handlers_block_by_func
2640 (G_OBJECT(folderview->ctree),
2641 G_CALLBACK(folderview_selected), folderview);
2644 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2645 GTK_CTREE(folderview->ctree), NULL, item);
2647 folderview_select(folderview, item);
2648 folderview->open_folder = FALSE;
2649 folderview->selected = node;
2652 g_signal_handlers_unblock_by_func
2653 (G_OBJECT(folderview->ctree),
2654 G_CALLBACK(folderview_selected), folderview);
2656 pos = gtk_scrolled_window_get_vadjustment(
2657 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2658 gtk_adjustment_set_value(pos, height);
2659 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2662 static void drag_state_stop(FolderView *folderview)
2664 if (folderview->drag_timer)
2665 g_source_remove(folderview->drag_timer);
2666 folderview->drag_timer = 0;
2667 folderview->drag_node = NULL;
2670 static gint folderview_defer_expand(FolderView *folderview)
2672 if (folderview->drag_node) {
2673 folderview_recollapse_nodes(folderview, folderview->drag_node);
2674 if (folderview->drag_item->collapsed) {
2675 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2676 folderview->nodes_to_recollapse = g_slist_append
2677 (folderview->nodes_to_recollapse, folderview->drag_node);
2680 folderview->drag_item = NULL;
2681 folderview->drag_timer = 0;
2685 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2687 /* the idea is that we call drag_state_start() whenever we want expansion to
2688 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2689 * we need to call drag_state_stop() */
2690 drag_state_stop(folderview);
2691 /* request expansion */
2692 if (0 != (folderview->drag_timer = g_timeout_add
2693 (prefs_common.hover_timeout,
2694 (GtkFunction)folderview_defer_expand,
2696 folderview->drag_node = node;
2697 folderview->drag_item = item;
2701 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2702 FolderView *folderview)
2704 GdkDragContext *context;
2706 g_return_if_fail(folderview != NULL);
2707 if (folderview->selected == NULL) return;
2708 if (folderview->nodes_to_recollapse)
2709 g_slist_free(folderview->nodes_to_recollapse);
2710 folderview->nodes_to_recollapse = NULL;
2711 context = gtk_drag_begin(widget, folderview->target_list,
2712 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2713 gtk_drag_set_icon_default(context);
2716 static void folderview_drag_data_get(GtkWidget *widget,
2717 GdkDragContext *drag_context,
2718 GtkSelectionData *selection_data,
2721 FolderView *folderview)
2725 gchar *source = NULL;
2726 if (info == TARGET_DUMMY) {
2727 for (cur = GTK_CLIST(folderview->ctree)->selection;
2728 cur != NULL; cur = cur->next) {
2729 item = gtk_ctree_node_get_row_data
2730 (GTK_CTREE(folderview->ctree),
2731 GTK_CTREE_NODE(cur->data));
2733 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2734 gtk_selection_data_set(selection_data,
2735 selection_data->target, 8,
2736 source, strlen(source));
2742 g_warning("unknown info %d\n", info);
2746 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2748 FolderUpdateData *hookdata;
2749 FolderView *folderview;
2753 folderview = (FolderView *) userdata;
2754 g_return_val_if_fail(hookdata != NULL, FALSE);
2755 g_return_val_if_fail(folderview != NULL, FALSE);
2757 ctree = folderview->ctree;
2758 g_return_val_if_fail(ctree != NULL, FALSE);
2760 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2761 folderview_create_folder_node(folderview, hookdata->item);
2762 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2763 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2764 NULL, folder_item_parent(hookdata->item));
2765 folderview_sort_folders(folderview, node, hookdata->folder);
2766 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2769 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2771 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2772 if (folderview->selected == node)
2773 folderview->selected = NULL;
2774 if (folderview->opened == node)
2775 folderview->opened = NULL;
2777 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2778 folderview_set(folderview);
2783 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2784 GdkDragContext *context,
2788 FolderView *folderview)
2791 FolderItem *item = NULL, *src_item = NULL;
2792 GtkCTreeNode *node = NULL;
2793 gboolean acceptable = FALSE;
2794 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2795 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2796 int height = (int)pos->page_size;
2797 int total_height = (int)pos->upper;
2798 int vpos = (int) pos->value;
2800 if (gtk_clist_get_selection_info
2801 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2802 GtkWidget *srcwidget;
2804 if (y > height - 24 && height + vpos < total_height)
2805 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2807 if (y < 48 && y > 0)
2808 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2810 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2811 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2812 src_item = folderview->summaryview->folder_item;
2814 srcwidget = gtk_drag_get_source_widget(context);
2815 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2816 /* comes from summaryview */
2817 /* we are copying messages, so only accept folder items that are not
2818 the source item, are no root items and can copy messages */
2819 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2820 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2821 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2823 } else if (srcwidget == folderview->ctree) {
2824 /* comes from folderview */
2825 /* we are moving folder items, only accept folders that are not
2826 the source items and can copy messages and create folder items */
2827 if (item && item->folder && src_item && src_item != item &&
2828 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2829 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2830 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2831 || item->folder == src_item->folder))
2834 /* comes from another app */
2835 /* we are adding messages, so only accept folder items that are
2836 no root items and can copy messages */
2837 if (item && item->folder && folder_item_parent(item) != NULL
2838 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2839 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2844 if (acceptable || (src_item && src_item == item))
2845 drag_state_start(folderview, node, item);
2848 g_signal_handlers_block_by_func
2850 G_CALLBACK(folderview_selected), folderview);
2851 gtk_ctree_select(GTK_CTREE(widget), node);
2852 g_signal_handlers_unblock_by_func
2854 G_CALLBACK(folderview_selected), folderview);
2855 gdk_drag_status(context,
2856 (context->actions == GDK_ACTION_COPY ?
2857 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2859 if (folderview->opened)
2860 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2861 gdk_drag_status(context, 0, time);
2867 static void folderview_drag_leave_cb(GtkWidget *widget,
2868 GdkDragContext *context,
2870 FolderView *folderview)
2872 drag_state_stop(folderview);
2873 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2876 static void free_info (gpointer stuff, gpointer data)
2881 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2882 guint time, FolderItem *item)
2885 GSList *msglist = NULL;
2886 list = uri_list_extract_filenames(data);
2887 if (!(item && item->folder && folder_item_parent(item) != NULL
2888 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2890 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2891 debug_print("item doesn't fit\n");
2895 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2896 debug_print("list is empty\n");
2899 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2900 MsgFileInfo *info = NULL;
2902 if (file_is_email((gchar *)tmp->data)) {
2903 info = g_new0(MsgFileInfo, 1);
2904 info->msginfo = NULL;
2905 info->file = (gchar *)tmp->data;
2906 msglist = g_slist_prepend(msglist, info);
2907 debug_print("file is a mail\n");
2909 debug_print("file isn't a mail\n");
2913 msglist = g_slist_reverse(msglist);
2914 folder_item_add_msgs(item, msglist, FALSE);
2915 g_slist_foreach(msglist, free_info, NULL);
2916 g_slist_free(msglist);
2917 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2919 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2921 list_free_strings(list);
2925 static void folderview_drag_received_cb(GtkWidget *widget,
2926 GdkDragContext *drag_context,
2929 GtkSelectionData *data,
2932 FolderView *folderview)
2935 FolderItem *item = NULL, *src_item;
2938 if (info == TARGET_DUMMY) {
2939 drag_state_stop(folderview);
2940 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2941 /* comes from summaryview */
2942 if (gtk_clist_get_selection_info
2943 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2946 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2947 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2948 src_item = folderview->summaryview->folder_item;
2950 /* re-check (due to acceptable possibly set for folder moves */
2951 if (!(item && item->folder && item->path && !item->no_select &&
2952 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2955 if (item && src_item) {
2956 switch (drag_context->action) {
2957 case GDK_ACTION_COPY:
2958 summary_copy_selected_to(folderview->summaryview, item);
2959 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2961 case GDK_ACTION_MOVE:
2962 case GDK_ACTION_DEFAULT:
2964 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2965 summary_copy_selected_to(folderview->summaryview, item);
2967 summary_move_selected_to(folderview->summaryview, item);
2968 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2971 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2973 /* comes from folderview */
2975 gboolean folder_is_normal = TRUE;
2976 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2978 source = data->data + 17;
2979 if (gtk_clist_get_selection_info
2980 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2982 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2985 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2986 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2987 src_item = folder_find_item_from_identifier(source);
2991 src_item->stype == F_NORMAL &&
2992 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2993 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2994 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2995 !folder_has_parent_of_type(src_item, F_TRASH);
2996 if (!item || item->no_select || !src_item
2997 || !folder_is_normal) {
2998 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3002 folderview_move_folder(folderview, src_item, item, copy);
3003 gtk_drag_finish(drag_context, TRUE, TRUE, time);
3005 folderview->nodes_to_recollapse = NULL;
3006 } else if (info == TARGET_MAIL_URI_LIST) {
3007 if (gtk_clist_get_selection_info
3008 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
3011 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
3013 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3014 debug_print("no node\n");
3017 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
3019 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3020 debug_print("no item\n");
3023 folderview_finish_dnd(data->data, drag_context, time, item);
3027 static void folderview_drag_end_cb(GtkWidget *widget,
3028 GdkDragContext *drag_context,
3029 FolderView *folderview)
3031 drag_state_stop(folderview);
3032 g_slist_free(folderview->nodes_to_recollapse);
3033 folderview->nodes_to_recollapse = NULL;
3036 void folderview_register_popup(FolderViewPopup *fpopup)
3040 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3041 FolderView *folderview = folderviews->data;
3042 GtkItemFactory *factory;
3044 factory = create_ifactory(folderview, fpopup);
3045 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
3047 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
3050 void folderview_unregister_popup(FolderViewPopup *fpopup)
3054 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3055 FolderView *folderview = folderviews->data;
3057 g_hash_table_remove(folderview->popups, fpopup->klass);
3059 g_hash_table_remove(folderview_popups, fpopup->klass);