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 3 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, see <http://www.gnu.org/licenses/>.
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],
479 gtk_clist_column_titles_hide(GTK_CLIST(ctree));
482 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
483 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
485 gtk_clist_set_column_justification(GTK_CLIST(ctree),
486 col_pos[F_COL_UNREAD],
488 gtk_clist_set_column_justification(GTK_CLIST(ctree),
489 col_pos[F_COL_TOTAL],
491 if (prefs_common.enable_dotted_lines) {
492 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
493 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
494 GTK_CTREE_EXPANDER_SQUARE);
496 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
497 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
498 GTK_CTREE_EXPANDER_TRIANGLE);
501 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
502 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
504 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
505 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
507 /* don't let title buttons take key focus */
508 for (i = 0; i < N_FOLDER_COLS; i++) {
509 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
511 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
512 prefs_common.folder_col_size[i]);
513 gtk_clist_set_column_visibility
514 (GTK_CLIST(ctree), i, col_state[i].visible);
517 g_signal_connect(G_OBJECT(ctree), "key_press_event",
518 G_CALLBACK(folderview_key_pressed),
520 g_signal_connect(G_OBJECT(ctree), "button_press_event",
521 G_CALLBACK(folderview_button_pressed),
524 g_signal_connect(G_OBJECT(ctree), "popup-menu",
525 G_CALLBACK(folderview_popup_menu), folderview);
527 gtk_widget_tap_and_hold_setup(GTK_WIDGET(ctree), NULL, NULL,
528 GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
529 g_signal_connect(G_OBJECT(ctree), "tap-and-hold",
530 G_CALLBACK(folderview_popup_menu), folderview);
532 g_signal_connect(G_OBJECT(ctree), "button_release_event",
533 G_CALLBACK(folderview_button_released),
535 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
536 G_CALLBACK(folderview_selected), folderview);
537 g_signal_connect(G_OBJECT(ctree), "start_drag",
538 G_CALLBACK(folderview_start_drag), folderview);
539 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
540 G_CALLBACK(folderview_drag_data_get),
543 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
544 G_CALLBACK(folderview_tree_expanded),
546 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
547 G_CALLBACK(folderview_tree_collapsed),
550 g_signal_connect(G_OBJECT(ctree), "resize_column",
551 G_CALLBACK(folderview_col_resized),
555 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
556 folderview_drag_types, 2,
557 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
558 g_signal_connect(G_OBJECT(ctree), "drag_motion",
559 G_CALLBACK(folderview_drag_motion_cb),
561 g_signal_connect(G_OBJECT(ctree), "drag_leave",
562 G_CALLBACK(folderview_drag_leave_cb),
564 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
565 G_CALLBACK(folderview_drag_received_cb),
567 g_signal_connect(G_OBJECT(ctree), "drag_end",
568 G_CALLBACK(folderview_drag_end_cb),
571 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
576 void folderview_set_column_order(FolderView *folderview)
579 FolderItem *item = folderview_get_selected_item(folderview);
580 GtkWidget *scrolledwin = folderview->scrolledwin;
582 debug_print("recreating tree...\n");
583 gtk_widget_destroy(folderview->ctree);
585 folderview->ctree = ctree = folderview_ctree_create(folderview);
586 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
587 GTK_CLIST(ctree)->hadjustment);
588 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
589 GTK_CLIST(ctree)->vadjustment);
590 gtk_widget_show(ctree);
592 folderview_set(folderview);
593 folderview_column_set_titles(folderview);
595 folderview_select(folderview,item);
598 FolderView *folderview_create(void)
600 FolderView *folderview;
601 GtkWidget *scrolledwin;
604 debug_print("Creating folder view...\n");
605 folderview = g_new0(FolderView, 1);
607 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
608 gtk_scrolled_window_set_policy
609 (GTK_SCROLLED_WINDOW(scrolledwin),
610 GTK_POLICY_AUTOMATIC,
611 prefs_common.folderview_vscrollbar_policy);
612 gtk_widget_set_size_request(scrolledwin,
613 prefs_common.folderview_width,
614 prefs_common.folderview_height);
616 folderview->scrolledwin = scrolledwin;
617 ctree = folderview_ctree_create(folderview);
619 /* create popup factories */
620 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
621 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
623 folderview->ctree = ctree;
625 folderview->folder_update_callback_id =
626 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
627 folderview->folder_item_update_callback_id =
628 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
630 gtk_widget_show_all(scrolledwin);
632 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
633 folderview_list = g_list_append(folderview_list, folderview);
634 folderview->deferred_refresh_id = -1;
639 void folderview_init(FolderView *folderview)
641 GtkWidget *ctree = folderview->ctree;
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
671 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
677 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
678 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
679 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
680 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
681 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
682 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
683 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
684 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
685 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
686 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
687 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
688 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
689 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
692 PangoFontDescription *font_desc;
693 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
694 font_desc = pango_font_description_from_string(NORMAL_FONT);
696 if (normal_style->font_desc)
697 pango_font_description_free
698 (normal_style->font_desc);
699 normal_style->font_desc = font_desc;
701 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
702 normal_color_style = gtk_style_copy(normal_style);
703 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
705 gtk_widget_set_style(ctree, normal_style);
709 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
710 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
711 pango_font_description_set_weight
712 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
713 bold_color_style = gtk_style_copy(bold_style);
714 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
716 bold_tgtfold_style = gtk_style_copy(bold_style);
717 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
721 static gboolean folderview_defer_set(gpointer data)
723 FolderView *folderview = (FolderView *)data;
724 MainWindow *mainwin = folderview->mainwin;
728 if (mainwin->lock_count)
731 printf("doing deferred folderview_set now\n");
732 folderview_set(folderview);
734 folderview->deferred_refresh_id = -1;
738 void folderview_set(FolderView *folderview)
740 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
741 MainWindow *mainwin = folderview->mainwin;
742 FolderItem *sel_item = NULL, *op_item = NULL;
747 if (mainwin->lock_count) {
748 if (folderview->deferred_refresh_id == -1)
749 folderview->deferred_refresh_id =
750 g_timeout_add(500, folderview_defer_set, folderview);
751 printf("deferred folderview_set\n");
756 debug_print("Setting folder info...\n");
757 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
759 main_window_cursor_wait(mainwin);
761 if (folderview->selected)
762 sel_item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
763 if (folderview->opened)
764 op_item = gtk_ctree_node_get_row_data(ctree, folderview->opened);
766 folderview->selected = NULL;
767 folderview->opened = NULL;
769 gtk_clist_freeze(GTK_CLIST(ctree));
770 gtk_clist_clear(GTK_CLIST(ctree));
772 folderview_set_folders(folderview);
775 folderview->selected = gtk_ctree_find_by_row_data(ctree, NULL, sel_item);
777 folderview->opened = gtk_ctree_find_by_row_data(ctree, NULL, op_item);
779 gtk_clist_thaw(GTK_CLIST(ctree));
780 main_window_cursor_normal(mainwin);
781 STATUSBAR_POP(mainwin);
785 void folderview_set_all(void)
789 for (list = folderview_list; list != NULL; list = list->next)
790 folderview_set((FolderView *)list->data);
793 void folderview_select(FolderView *folderview, FolderItem *item)
795 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
797 GtkCTreeNode *old_selected = folderview->selected;
801 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
802 if (node) folderview_select_node(folderview, node);
804 if (old_selected != node)
805 folder_update_op_count();
808 static void mark_all_read_cb(FolderView *folderview, guint action,
814 item = folderview_get_selected_item(folderview);
818 if (folderview->summaryview->folder_item != item
819 && prefs_common.ask_mark_all_read) {
820 val = alertpanel_full(_("Mark all as read"),
821 _("Do you really want to mark all mails in this "
822 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
823 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
825 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
827 else if (val & G_ALERTDISABLE)
828 prefs_common.ask_mark_all_read = FALSE;
831 summary_lock(folderview->summaryview);
832 folder_item_update_freeze();
833 if (folderview->summaryview->folder_item == item)
834 summary_freeze(folderview->summaryview);
835 folderutils_mark_all_read(item);
836 if (folderview->summaryview->folder_item == item)
837 summary_thaw(folderview->summaryview);
838 folder_item_update_thaw();
839 summary_unlock(folderview->summaryview);
842 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
844 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
846 g_return_if_fail(node != NULL);
848 if (folderview->open_folder) {
852 folderview->open_folder = TRUE;
853 gtkut_ctree_set_focus_row(ctree, node);
854 gtk_ctree_select(ctree, node);
855 if (folderview->summaryview->folder_item &&
856 folderview->summaryview->folder_item->total_msgs > 0)
857 summary_grab_focus(folderview->summaryview);
859 gtk_widget_grab_focus(folderview->ctree);
861 gtkut_ctree_expand_parent_all(ctree, node);
864 void folderview_unselect(FolderView *folderview)
866 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
868 (GTK_CTREE(folderview->ctree), folderview->opened);
870 folderview->selected = folderview->opened = NULL;
873 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
879 node = gtkut_ctree_node_next(ctree, node);
881 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
883 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
884 item = gtk_ctree_node_get_row_data(ctree, node);
885 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
892 void folderview_select_next_marked(FolderView *folderview)
894 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
895 GtkCTreeNode *node = NULL;
896 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
897 gboolean last_open = prefs_common.always_show_msg;
899 prefs_common.summary_select_prio[0] = ACTION_MARKED;
900 prefs_common.always_show_msg = TRUE;
902 if ((node = folderview_find_next_marked(ctree, folderview->opened))
904 folderview_select_node(folderview, node);
908 if (!folderview->opened ||
909 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
912 /* search again from the first node */
913 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
914 folderview_select_node(folderview, node);
917 prefs_common.summary_select_prio[0] = last_summary_select_prio;
918 prefs_common.always_show_msg = last_open;
921 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
927 node = gtkut_ctree_node_next(ctree, node);
929 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
931 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
932 item = gtk_ctree_node_get_row_data(ctree, node);
933 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
940 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
942 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
943 GtkCTreeNode *node = NULL;
944 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
945 gboolean last_open = prefs_common.always_show_msg;
947 prefs_common.summary_select_prio[0] = ACTION_UNREAD;
948 prefs_common.always_show_msg = force_open ? TRUE : last_open;
950 if ((node = folderview_find_next_unread(ctree, folderview->opened))
952 folderview_select_node(folderview, node);
956 if (!folderview->opened ||
957 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
960 /* search again from the first node */
961 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
962 folderview_select_node(folderview, node);
965 prefs_common.summary_select_prio[0] = last_summary_select_prio;
966 prefs_common.always_show_msg = last_open;
969 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
975 node = gtkut_ctree_node_next(ctree, node);
977 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
979 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
980 item = gtk_ctree_node_get_row_data(ctree, node);
981 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
988 void folderview_select_next_new(FolderView *folderview)
990 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
991 GtkCTreeNode *node = NULL;
992 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
993 gboolean last_open = prefs_common.always_show_msg;
995 prefs_common.summary_select_prio[0] = ACTION_NEW;
996 prefs_common.always_show_msg = TRUE;
998 if ((node = folderview_find_next_new(ctree, folderview->opened))
1000 folderview_select_node(folderview, node);
1004 if (!folderview->opened ||
1005 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
1008 /* search again from the first node */
1009 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
1010 folderview_select_node(folderview, node);
1013 prefs_common.summary_select_prio[0] = last_summary_select_prio;
1014 prefs_common.always_show_msg = last_open;
1017 FolderItem *folderview_get_selected_item(FolderView *folderview)
1019 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1021 if (!folderview->selected) return NULL;
1022 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
1025 static void folderview_set_folders(FolderView *folderview)
1028 list = folder_get_list();
1030 for (; list != NULL; list = list->next) {
1031 folderview_append_folder(folderview, FOLDER(list->data));
1035 static gchar *get_scan_str(FolderItem *item)
1038 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1039 item->folder->name, G_DIR_SEPARATOR,
1042 return g_strdup_printf(_("Scanning folder %s ..."),
1043 item->folder->name);
1045 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1049 for (list = folderview_list; list != NULL; list = list->next) {
1050 FolderView *folderview = (FolderView *)list->data;
1051 MainWindow *mainwin = folderview->mainwin;
1052 gchar *str = get_scan_str(item);
1054 STATUSBAR_PUSH(mainwin, str);
1055 STATUSBAR_POP(mainwin);
1060 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1063 MainWindow *mainwin = mainwindow_get_mainwindow();
1064 FolderView *folderview = NULL;
1065 GtkAdjustment *pos = NULL;
1068 g_return_if_fail(folder != NULL);
1070 if (!folder->klass->scan_tree) return;
1073 alertpanel_full(_("Rebuild folder tree"),
1074 _("Rebuilding the folder tree will remove "
1075 "local caches. Do you want to continue?"),
1076 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1077 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1078 != G_ALERTALTERNATE) {
1084 window = label_window_create(_("Rebuilding folder tree..."));
1086 window = label_window_create(_("Scanning folder tree..."));
1089 folderview = mainwin->folderview;
1092 pos = gtk_scrolled_window_get_vadjustment(
1093 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1094 height = pos->value;
1097 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1098 folder_scan_tree(folder, rebuild);
1099 folder_set_ui_func(folder, NULL, NULL);
1101 folderview_set_all();
1104 pos = gtk_scrolled_window_get_vadjustment(
1105 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1106 gtk_adjustment_set_value(pos, height);
1108 label_window_destroy(window);
1112 void folderview_fast_rescan_tree(Folder *folder)
1115 MainWindow *mainwin = mainwindow_get_mainwindow();
1116 FolderView *folderview = NULL;
1117 GtkAdjustment *pos = NULL;
1120 g_return_if_fail(folder != NULL);
1122 if (!folder->klass->scan_tree) return;
1126 window = label_window_create(_("Scanning folder tree..."));
1129 folderview = mainwin->folderview;
1132 pos = gtk_scrolled_window_get_vadjustment(
1133 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1134 height = pos->value;
1137 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1138 folder_fast_scan_tree(folder);
1139 folder_set_ui_func(folder, NULL, NULL);
1141 folderview_set_all();
1144 pos = gtk_scrolled_window_get_vadjustment(
1145 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1146 gtk_adjustment_set_value(pos, height);
1148 label_window_destroy(window);
1152 /** folderview_check_new()
1153 * Scan and update the folder and return the
1154 * count the number of new messages since last check.
1155 * \param folder the folder to check for new messages
1156 * \return the number of new messages since last check
1158 gint folderview_check_new(Folder *folder)
1162 FolderView *folderview;
1166 gint former_new_msgs = 0;
1167 gint former_new = 0, former_unread = 0, former_total;
1169 for (list = folderview_list; list != NULL; list = list->next) {
1170 folderview = (FolderView *)list->data;
1171 ctree = GTK_CTREE(folderview->ctree);
1174 main_window_lock(folderview->mainwin);
1176 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1177 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1179 item = gtk_ctree_node_get_row_data(ctree, node);
1180 if (!item || !item->path || !item->folder) continue;
1181 if (item->no_select) continue;
1182 if (folder && folder != item->folder) continue;
1183 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1184 if (!item->prefs->newmailcheck) continue;
1185 if (item->processing_pending == TRUE) {
1186 debug_print("skipping %s, processing pending\n",
1187 item->path ? item->path : item->name);
1191 str = get_scan_str(item);
1193 STATUSBAR_PUSH(folderview->mainwin, str);
1197 folderview_scan_tree_func(item->folder, item, NULL);
1198 former_new = item->new_msgs;
1199 former_unread = item->unread_msgs;
1200 former_total = item->total_msgs;
1202 if (item->folder->klass->scan_required &&
1203 (item->folder->klass->scan_required(item->folder, item) ||
1204 item->folder->inbox == item ||
1205 item->opened == TRUE ||
1206 item->processing_pending == TRUE)) {
1207 if (folder_item_scan(item) < 0) {
1209 summaryview_unlock(folderview->summaryview, item);
1210 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1211 log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
1212 item->path ? item->path:item->name);
1213 STATUSBAR_POP(folderview->mainwin);
1215 } else if (!FOLDER_IS_LOCAL(folder)) {
1216 STATUSBAR_POP(folderview->mainwin);
1221 } else if (!item->folder->klass->scan_required) {
1222 if (folder_item_scan(item) < 0) {
1223 summaryview_unlock(folderview->summaryview, item);
1224 if (folder && !FOLDER_IS_LOCAL(folder)) {
1225 STATUSBAR_POP(folderview->mainwin);
1230 if (former_new != item->new_msgs ||
1231 former_unread != item->unread_msgs ||
1232 former_total != item->total_msgs)
1233 folderview_update_node(folderview, node);
1235 new_msgs += item->new_msgs;
1236 former_new_msgs += former_new;
1237 STATUSBAR_POP(folderview->mainwin);
1240 main_window_unlock(folderview->mainwin);
1244 folder_write_list();
1245 /* Number of new messages since last check is the just the difference
1246 * between former_new_msgs and new_msgs. If new_msgs is less than
1247 * former_new_msgs, that would mean another session accessed the folder
1248 * and the result is not well defined.
1250 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1254 void folderview_check_new_all(void)
1258 FolderView *folderview;
1260 folderview = (FolderView *)folderview_list->data;
1263 main_window_lock(folderview->mainwin);
1264 window = label_window_create
1265 (_("Checking for new messages in all folders..."));
1267 list = folder_get_list();
1268 for (; list != NULL; list = list->next) {
1269 Folder *folder = list->data;
1271 folderview_check_new(folder);
1274 folder_write_list();
1275 folderview_set_all();
1277 label_window_destroy(window);
1278 main_window_unlock(folderview->mainwin);
1282 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1288 if (!item || !item->folder || !item->folder->node)
1291 node = item->folder->node;
1293 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1294 node = node->children;
1297 (item->new_msgs > 0 ||
1298 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1302 while (node != NULL) {
1303 if (node && node->data) {
1304 FolderItem *next_item = (FolderItem*) node->data;
1306 if (folderview_have_new_children_sub(folderview,
1315 static gboolean folderview_have_new_children(FolderView *folderview,
1318 return folderview_have_new_children_sub(folderview, item, FALSE);
1321 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1327 if (!item || !item->folder || !item->folder->node)
1330 node = item->folder->node;
1332 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1333 node = node->children;
1336 (item->unread_msgs > 0 ||
1337 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1341 while (node != NULL) {
1342 if (node && node->data) {
1343 FolderItem *next_item = (FolderItem*) node->data;
1345 if (folderview_have_unread_children_sub(folderview,
1355 static gboolean folderview_have_unread_children(FolderView *folderview,
1358 return folderview_have_unread_children_sub(folderview, item, FALSE);
1361 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1367 if (!item || !item->folder || !item->folder->node)
1370 node = item->folder->node;
1372 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1373 node = node->children;
1375 if (in_sub && item->search_match){
1379 while (node != NULL) {
1380 if (node && node->data) {
1381 FolderItem *next_item = (FolderItem*) node->data;
1383 if (folderview_have_matching_children_sub(folderview,
1393 static gboolean folderview_have_matching_children(FolderView *folderview,
1396 return folderview_have_matching_children_sub(folderview, item, FALSE);
1399 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1405 if (!item || !item->folder || !item->folder->node)
1408 node = item->folder->node;
1410 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1411 node = node->children;
1413 if (item->marked_msgs != 0) {
1417 while (node != NULL) {
1418 if (node && node->data) {
1419 FolderItem *next_item = (FolderItem*) node->data;
1421 if (folderview_have_marked_children_sub(folderview,
1430 static gboolean folderview_have_marked_children(FolderView *folderview,
1433 return folderview_have_marked_children_sub(folderview, item, FALSE);
1436 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1438 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1439 GtkStyle *style = NULL;
1440 GtkStyle *color_style = NULL;
1442 GdkPixmap *xpm, *openxpm;
1443 GdkBitmap *mask, *openmask;
1444 static GdkPixmap *searchicon;
1445 static GdkBitmap *searchmask;
1446 gboolean mark = FALSE;
1449 gboolean add_unread_mark;
1450 gboolean add_sub_match_mark;
1451 gboolean use_bold, use_color;
1452 gint *col_pos = folderview->col_pos;
1453 SpecialFolderItemType stype;
1455 item = gtk_ctree_node_get_row_data(ctree, node);
1456 g_return_if_fail(item != NULL);
1458 if (!GTK_CTREE_ROW(node)->expanded)
1459 mark = folderview_have_marked_children(folderview, item);
1461 mark = (item->marked_msgs != 0);
1463 stype = item->stype;
1464 if (stype == F_NORMAL) {
1465 if (folder_has_parent_of_type(item, F_TRASH))
1467 else if (folder_has_parent_of_type(item, F_DRAFT))
1469 else if (folder_has_parent_of_type(item, F_OUTBOX))
1471 else if (folder_has_parent_of_type(item, F_QUEUE))
1476 if (item->hide_read_msgs) {
1477 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1478 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1479 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1480 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1482 xpm = mark?m_inboxxpm:inboxxpm;
1483 mask = mark?m_inboxxpmmask:inboxxpmmask;
1484 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1485 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1489 if (item->hide_read_msgs) {
1490 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1491 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1492 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1493 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1495 xpm = mark?m_outboxxpm:outboxxpm;
1496 mask = mark?m_outboxxpmmask:outboxxpmmask;
1497 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1498 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1502 if (item->hide_read_msgs) {
1503 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1504 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1505 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1506 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1508 xpm = mark?m_queuexpm:queuexpm;
1509 mask = mark?m_queuexpmmask:queuexpmmask;
1510 openxpm = mark?m_queueopenxpm:queueopenxpm;
1511 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1515 if (item->hide_read_msgs) {
1516 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1517 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1518 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1519 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1521 xpm = mark?m_trashxpm:trashxpm;
1522 mask = mark?m_trashxpmmask:trashxpmmask;
1523 openxpm = mark?m_trashopenxpm:trashopenxpm;
1524 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1528 xpm = mark?m_draftsxpm:draftsxpm;
1529 mask = mark?m_draftsxpmmask:draftsxpmmask;
1530 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1531 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1534 if (item->hide_read_msgs) {
1535 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1536 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1537 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1538 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1540 xpm = mark?m_folderxpm:folderxpm;
1541 mask = mark?m_folderxpmmask:folderxpmmask;
1542 openxpm = mark?m_folderopenxpm:folderopenxpm;
1543 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1547 if (item->no_select) {
1548 xpm = openxpm = noselectxpm;
1549 mask = openmask = noselectxpmmask;
1552 name = folder_item_get_name(item);
1554 if (!GTK_CTREE_ROW(node)->expanded) {
1555 add_unread_mark = folderview_have_unread_children(
1557 add_sub_match_mark = folderview_have_matching_children(
1560 add_unread_mark = FALSE;
1561 add_sub_match_mark = FALSE;
1564 if (item->search_match) {
1566 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1567 &searchicon, &searchmask);
1569 xpm = openxpm = searchicon;
1570 mask = openmask = searchmask;
1574 if (prefs_common.display_folder_unread) {
1575 if (folder_has_parent_of_type(item, F_QUEUE)) {
1576 /* only total_msgs matters here */
1577 if (item->total_msgs > 0) {
1578 /* show total number (should be equal to the unread number)
1580 str = g_strdup_printf("%s (%d%s%s)",
1581 name, item->total_msgs,
1582 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1583 (item->unreadmarked_msgs > 0) ? "!" : "");
1586 if (prefs_common.display_folder_unread == 1) {
1587 if (item->unread_msgs > 0) {
1588 /* show unread number and signs */
1589 str = g_strdup_printf("%s (%d%s%s)",
1590 name, item->unread_msgs,
1591 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1592 (item->unreadmarked_msgs > 0) ? "!" : "");
1595 if (item->total_msgs > 0) {
1596 /* show unread number, total number and signs if any */
1597 str = g_strdup_printf("%s (%d/%d%s%s)",
1598 name, item->unread_msgs, item->total_msgs,
1599 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1600 (item->unreadmarked_msgs > 0) ? "!" : "");
1604 if ((str == NULL) &&
1605 (add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
1606 /* no unread/total numbers, but at least one sign */
1607 str = g_strdup_printf("%s (%s%s)",
1609 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1610 (item->unreadmarked_msgs > 0) ? "!" : "");
1614 /* last fallback, folder name only or with ! sign */
1615 str = g_strdup_printf("%s%s",
1616 name, (item->unreadmarked_msgs > 0) ? " (!)" : "");
1618 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1619 xpm, mask, openxpm, openmask,
1620 FALSE, GTK_CTREE_ROW(node)->expanded);
1624 if (!folder_item_parent(item)) {
1625 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1626 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1627 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1629 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], item->new_msgs > 0 ? itos(item->new_msgs) : prefs_common.zero_replacement);
1630 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
1631 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], item->total_msgs > 0 ? itos(item->total_msgs) : prefs_common.zero_replacement);
1634 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1635 folder_has_parent_of_type(item, F_DRAFT) ||
1636 folder_has_parent_of_type(item, F_TRASH)) {
1637 use_bold = use_color = FALSE;
1638 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1639 /* highlight queue folder if there are any messages */
1640 use_bold = use_color = (item->total_msgs > 0);
1642 /* if unread messages exist, print with bold font */
1643 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1645 /* if new messages exist, print with colored letter */
1647 (item->new_msgs > 0) ||
1649 folderview_have_new_children(folderview, item));
1652 gtk_ctree_node_set_foreground(ctree, node, NULL);
1657 if (item->prefs->color > 0 && !use_color) {
1658 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1659 color_style = gtk_style_copy(bold_style);
1660 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1661 style = color_style;
1662 } else if (use_color) {
1663 style = bold_color_style;
1666 if (item->op_count > 0) {
1667 style = bold_tgtfold_style;
1669 } else if (use_color) {
1670 style = normal_color_style;
1671 gtk_ctree_node_set_foreground(ctree, node,
1672 &folderview->color_new);
1673 } else if (item->op_count > 0) {
1674 style = bold_tgtfold_style;
1675 } else if (item->prefs->color > 0) {
1677 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1678 color_style = gtk_style_copy(normal_style);
1679 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1680 style = color_style;
1682 style = normal_style;
1685 gtk_ctree_node_set_row_style(ctree, node, style);
1687 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1688 folderview_update_node(folderview, node);
1691 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1694 FolderView *folderview;
1698 g_return_if_fail(item != NULL);
1700 for (list = folderview_list; list != NULL; list = list->next) {
1701 folderview = (FolderView *)list->data;
1702 ctree = GTK_CTREE(folderview->ctree);
1704 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1706 item->search_match = matches;
1707 folderview_update_node(folderview, node);
1712 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1714 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1715 FolderView *folderview = (FolderView *)data;
1718 g_return_val_if_fail(update_info != NULL, TRUE);
1719 g_return_val_if_fail(update_info->item != NULL, TRUE);
1720 g_return_val_if_fail(folderview != NULL, FALSE);
1722 ctree = GTK_CTREE(folderview->ctree);
1724 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1727 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1728 folderview_update_node(folderview, node);
1730 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
1731 update_info->item == folderview->summaryview->folder_item &&
1732 update_info->item != NULL)
1733 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1734 summary_show(folderview->summaryview, update_info->item);
1740 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1741 GNode *gnode, GtkCTreeNode *cnode,
1744 FolderView *folderview = (FolderView *)data;
1745 FolderItem *item = FOLDER_ITEM(gnode->data);
1747 g_return_val_if_fail(item != NULL, FALSE);
1749 gtk_ctree_node_set_row_data(ctree, cnode, item);
1750 folderview_update_node(folderview, cnode);
1755 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1758 FolderView *folderview = (FolderView *)data;
1761 if (GTK_CTREE_ROW(node)->children) {
1762 item = gtk_ctree_node_get_row_data(ctree, node);
1763 g_return_if_fail(item != NULL);
1765 if (!item->collapsed)
1766 gtk_ctree_expand(ctree, node);
1768 folderview_update_node(folderview, node);
1772 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1773 GtkCTreeNode *root, GtkCTreeNode **prev)
1776 GtkCTreeNode *node, *parent, *sibling;
1778 node = gtk_ctree_find_by_row_data(ctree, root, item);
1780 g_warning("%s not found.\n", item->path);
1782 parent = GTK_CTREE_ROW(node)->parent;
1783 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1784 sibling = GTK_CTREE_ROW(*prev)->sibling;
1786 sibling = GTK_CTREE_ROW(parent)->children;
1790 tmp = gtk_ctree_node_get_row_data
1792 if (tmp->stype != F_NORMAL)
1793 sibling = GTK_CTREE_ROW(sibling)->sibling;
1797 if (node != sibling)
1798 gtk_ctree_move(ctree, node, parent, sibling);
1805 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1808 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1809 GtkCTreeNode *prev = NULL;
1811 gtk_clist_freeze(GTK_CLIST(ctree));
1812 gtk_sctree_sort_recursive(ctree, root);
1813 if (root && GTK_CTREE_ROW(root)->parent) {
1814 gtk_clist_thaw(GTK_CLIST(ctree));
1817 set_special_folder(ctree, folder->inbox, root, &prev);
1818 set_special_folder(ctree, folder->outbox, root, &prev);
1819 set_special_folder(ctree, folder->draft, root, &prev);
1820 set_special_folder(ctree, folder->queue, root, &prev);
1821 set_special_folder(ctree, folder->trash, root, &prev);
1822 gtk_clist_thaw(GTK_CLIST(ctree));
1825 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1827 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1830 g_return_if_fail(folder != NULL);
1832 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1833 folderview_gnode_func, folderview);
1834 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1836 folderview_sort_folders(folderview, root, folder);
1839 /* callback functions */
1840 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1841 GdkEventButton *event)
1843 GtkCList *clist = GTK_CLIST(folderview->ctree);
1846 FolderViewPopup *fpopup;
1847 GtkItemFactory *fpopup_factory;
1849 FolderItem *special_trash = NULL, *special_queue = NULL;
1853 item = gtk_clist_get_row_data(clist, row);
1855 item = folderview_get_selected_item(folderview);
1857 g_return_if_fail(item != NULL);
1858 g_return_if_fail(item->folder != NULL);
1859 folder = item->folder;
1861 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1863 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1865 fpopup = g_hash_table_lookup(folderview_popups, "common");
1866 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1869 if (fpopup->set_sensitivity != NULL)
1870 fpopup->set_sensitivity(fpopup_factory, item);
1872 if (NULL != (ac = account_find_from_item(item))) {
1873 special_trash = account_get_special_folder(ac, F_TRASH);
1874 special_queue = account_get_special_folder(ac, F_QUEUE);
1877 if ((item == folder->trash || item == special_trash
1878 || folder_has_parent_of_type(item, F_TRASH)) &&
1879 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1880 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1881 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1882 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1883 && !folder_has_parent_of_type(item, F_TRASH)) {
1884 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1885 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1888 if ((item == folder->queue || item == special_queue
1889 || folder_has_parent_of_type(item, F_QUEUE)) &&
1890 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1891 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1892 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1893 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1894 && !folder_has_parent_of_type(item, F_QUEUE)) {
1895 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1896 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1899 #define SET_SENS(name, sens) \
1900 menu_set_sensitive(fpopup_factory, name, sens)
1902 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1903 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1904 folderview->selected == folderview->opened);
1905 SET_SENS("/Properties...", TRUE);
1906 SET_SENS("/Processing...", item->node->parent != NULL);
1907 if (item == folder->trash || item == special_trash
1908 || folder_has_parent_of_type(item, F_TRASH)) {
1909 GSList *msglist = folder_item_get_msg_list(item);
1910 SET_SENS("/Empty trash...", msglist != NULL);
1911 procmsg_msg_list_free(msglist);
1913 if (item == folder->queue || item == special_queue
1914 || folder_has_parent_of_type(item, F_QUEUE)) {
1915 GSList *msglist = folder_item_get_msg_list(item);
1916 SET_SENS("/Send queue...", msglist != NULL);
1917 procmsg_msg_list_free(msglist);
1921 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1922 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1923 event->button, event->time);
1928 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1929 FolderView *folderview)
1931 GtkCList *clist = GTK_CLIST(ctree);
1932 gint prev_row = -1, row = -1, column = -1;
1934 if (!event) return FALSE;
1936 if (event->button == 1 || event->button == 2) {
1937 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1938 folderview->open_folder = TRUE;
1940 if (event->type == GDK_2BUTTON_PRESS) {
1941 if (clist->selection) {
1944 node = GTK_CTREE_NODE(clist->selection->data);
1946 gtk_ctree_toggle_expansion(
1949 folderview->open_folder = FALSE;
1956 if (event->button == 2 || event->button == 3) {
1958 if (clist->selection) {
1961 node = GTK_CTREE_NODE(clist->selection->data);
1963 prev_row = gtkut_ctree_get_nth_from_node
1964 (GTK_CTREE(ctree), node);
1967 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1970 if (prev_row != row) {
1971 gtk_clist_unselect_all(clist);
1972 if (event->button == 2)
1973 folderview_select_node
1975 gtk_ctree_node_nth(GTK_CTREE(ctree),
1978 gtk_clist_select_row(clist, row, column);
1982 if (event->button != 3) return FALSE;
1984 folderview_set_sens_and_popup_menu(folderview, row, event);
1988 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1989 FolderView *folderview)
1991 if (!event) return FALSE;
1993 if (event->button == 1 && folderview->open_folder == FALSE &&
1994 folderview->opened != NULL) {
1995 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1996 folderview->opened);
1997 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
2003 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
2004 FolderView *folderview)
2006 if (!event) return FALSE;
2008 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
2011 switch (event->keyval) {
2017 if (folderview->selected) {
2018 folderview_select_node(folderview,
2019 folderview->selected);
2024 if (folderview->selected && GTK_CTREE_ROW(folderview->selected)->children) {
2025 gtk_ctree_toggle_expansion(
2026 GTK_CTREE(folderview->ctree),
2027 folderview->selected);
2032 if (folderview->selected) {
2033 if (folderview->opened == folderview->selected &&
2034 (!folderview->summaryview->folder_item ||
2035 folderview->summaryview->folder_item->total_msgs == 0))
2036 folderview_select_next_unread(folderview, TRUE);
2038 folderview_select_node(folderview,
2039 folderview->selected);
2049 typedef struct _PostponedSelectData
2054 FolderView *folderview;
2055 } PostponedSelectData;
2057 static gboolean postpone_select(void *data)
2059 PostponedSelectData *psdata = (PostponedSelectData *)data;
2060 debug_print("trying again\n");
2061 psdata->folderview->open_folder = TRUE;
2062 main_window_cursor_normal(psdata->folderview->mainwin);
2063 STATUSBAR_POP(psdata->folderview->mainwin);
2064 folderview_selected(psdata->ctree, psdata->row,
2065 psdata->column, psdata->folderview);
2070 void folderview_close_opened(FolderView *folderview)
2072 if (folderview->opened) {
2073 FolderItem *olditem;
2075 olditem = gtk_ctree_node_get_row_data(GTK_CTREE(folderview->ctree),
2076 folderview->opened);
2078 gchar *buf = g_strdup_printf(_("Closing Folder %s..."),
2079 olditem->path ? olditem->path:olditem->name);
2080 /* will be null if we just moved the previously opened folder */
2081 STATUSBAR_PUSH(folderview->mainwin, buf);
2082 main_window_cursor_wait(folderview->mainwin);
2084 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2085 summary_show(folderview->summaryview, NULL);
2086 folder_item_close(olditem);
2087 main_window_cursor_normal(folderview->mainwin);
2088 STATUSBAR_POP(folderview->mainwin);
2092 if (folderview->opened &&
2093 !GTK_CTREE_ROW(folderview->opened)->children)
2094 gtk_ctree_collapse(GTK_CTREE(folderview->ctree), folderview->opened);
2096 folderview->opened = NULL;
2098 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2099 gint column, FolderView *folderview)
2101 static gboolean can_select = TRUE; /* exclusive lock */
2106 GtkCTreeNode *old_opened = folderview->opened;
2108 folderview->selected = row;
2110 debug_print("newly selected %p, opened %p\n", folderview->selected,
2111 folderview->opened);
2112 if (folderview->opened == row) {
2113 folderview->open_folder = FALSE;
2118 if (!can_select || summary_is_locked(folderview->summaryview)) {
2119 if (folderview->opened) {
2120 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2121 gtk_ctree_select(ctree, folderview->opened);
2123 folderview->open_folder = FALSE;
2128 if (!folderview->open_folder) {
2132 item = gtk_ctree_node_get_row_data(ctree, row);
2133 if (!item || item->no_select) {
2135 folderview->open_folder = FALSE;
2141 /* Save cache for old folder */
2142 /* We don't want to lose all caches if sylpheed crashed */
2143 /* resets folderview->opened to NULL */
2144 folderview_close_opened(folderview);
2146 /* CLAWS: set compose button type: news folder items
2147 * always have a news folder as parent */
2149 toolbar_set_compose_button
2150 (folderview->mainwin->toolbar,
2151 FOLDER_TYPE(item->folder) == F_NEWS ?
2152 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2155 debug_print("Folder %s is selected\n", item->path);
2157 if (!GTK_CTREE_ROW(row)->children)
2158 gtk_ctree_expand(ctree, row);
2160 /* ungrab the mouse event */
2161 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2162 gtk_grab_remove(GTK_WIDGET(ctree));
2163 if (gdk_pointer_is_grabbed())
2164 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2168 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2169 item->path : "(null)");
2170 debug_print("%s\n", buf);
2171 STATUSBAR_PUSH(folderview->mainwin, buf);
2174 main_window_cursor_wait(folderview->mainwin);
2176 res = folder_item_open(item);
2178 main_window_cursor_normal(folderview->mainwin);
2179 STATUSBAR_POP(folderview->mainwin);
2181 alertpanel_error(_("Folder could not be opened."));
2183 folderview->open_folder = FALSE;
2187 } else if (res == -2) {
2188 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2189 data->ctree = ctree;
2191 data->column = column;
2192 data->folderview = folderview;
2193 debug_print("postponing open of %s till end of scan\n",
2194 item->path ? item->path:item->name);
2195 folderview->open_folder = FALSE;
2197 g_timeout_add(500, postpone_select, data);
2202 main_window_cursor_normal(folderview->mainwin);
2205 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2206 opened = summary_show(folderview->summaryview, item);
2208 folder_clean_cache_memory(item);
2211 gtkut_ctree_set_focus_row(ctree, old_opened);
2212 gtk_ctree_select(ctree, old_opened);
2213 folderview->opened = old_opened;
2215 folderview->opened = row;
2216 if (gtk_ctree_node_is_visible(ctree, row)
2217 != GTK_VISIBILITY_FULL)
2218 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2221 STATUSBAR_POP(folderview->mainwin);
2223 folderview->open_folder = FALSE;
2228 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2229 FolderView *folderview)
2233 item = gtk_ctree_node_get_row_data(ctree, node);
2234 g_return_if_fail(item != NULL);
2235 item->collapsed = FALSE;
2236 folderview_update_node(folderview, node);
2239 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2240 FolderView *folderview)
2244 item = gtk_ctree_node_get_row_data(ctree, node);
2245 g_return_if_fail(item != NULL);
2246 item->collapsed = TRUE;
2247 folderview_update_node(folderview, node);
2250 static void folderview_popup_close(GtkMenuShell *menu_shell,
2251 FolderView *folderview)
2253 if (!folderview->opened) return;
2255 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2258 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2259 FolderView *folderview)
2261 FolderColumnType type = folderview->col_state[column].type;
2263 prefs_common.folder_col_size[type] = width;
2266 static void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2270 folderview_create_folder_node(folderview, item);
2272 if (!item || !item->folder || !item->folder->node)
2275 srcnode = item->folder->node;
2276 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2277 srcnode = srcnode->children;
2278 while (srcnode != NULL) {
2279 if (srcnode && srcnode->data) {
2280 FolderItem *next_item = (FolderItem*) srcnode->data;
2281 folderview_create_folder_node_recursive(folderview, next_item);
2283 srcnode = srcnode->next;
2287 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2289 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2290 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2291 GtkCTreeNode *node, *parent_node;
2292 gint *col_pos = folderview->col_pos;
2293 FolderItemUpdateData hookdata;
2295 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2296 if (parent_node == NULL)
2299 gtk_clist_freeze(GTK_CLIST(ctree));
2301 text[col_pos[F_COL_FOLDER]] = item->name;
2302 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2304 folderxpm, folderxpmmask,
2305 folderopenxpm, folderopenxpmmask,
2307 gtk_ctree_expand(ctree, parent_node);
2308 gtk_ctree_node_set_row_data(ctree, node, item);
2310 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2311 folderview_sort_folders(folderview, parent_node, item->folder);
2313 hookdata.item = item;
2314 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2315 hookdata.msg = NULL;
2316 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2318 gtk_clist_thaw(GTK_CLIST(ctree));
2321 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2324 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2326 GSList *mlist = NULL;
2328 FolderItem *special_trash = NULL;
2331 if (!folderview->selected) return;
2332 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2333 g_return_if_fail(item != NULL);
2334 g_return_if_fail(item->folder != NULL);
2336 if (NULL != (ac = account_find_from_item(item)))
2337 special_trash = account_get_special_folder(ac, F_TRASH);
2339 if (item != item->folder->trash && item != special_trash
2340 && !folder_has_parent_of_type(item, F_TRASH)) return;
2342 if (prefs_common.ask_on_clean) {
2343 if (alertpanel(_("Empty trash"),
2344 _("Delete all messages in trash?"),
2345 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2349 mlist = folder_item_get_msg_list(item);
2351 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2352 MsgInfo * msginfo = (MsgInfo *) cur->data;
2353 if (MSG_IS_LOCKED(msginfo->flags))
2355 /* is it partially received? (partial_recv isn't cached) */
2356 if (msginfo->total_size != 0 &&
2357 msginfo->size != (off_t)msginfo->total_size)
2358 partial_mark_for_delete(msginfo);
2360 procmsg_msg_list_free(mlist);
2362 folder_item_remove_all_msg(item);
2365 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2368 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2370 FolderItem *special_queue = NULL;
2372 gchar *errstr = NULL;
2374 if (!folderview->selected) return;
2375 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2376 g_return_if_fail(item != NULL);
2377 g_return_if_fail(item->folder != NULL);
2379 if (NULL != (ac = account_find_from_item(item)))
2380 special_queue = account_get_special_folder(ac, F_QUEUE);
2382 if (item != item->folder->queue && item != special_queue
2383 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2385 if (procmsg_queue_is_empty(item))
2388 if (prefs_common.work_offline)
2389 if (alertpanel(_("Offline warning"),
2390 _("You're working offline. Override?"),
2391 GTK_STOCK_NO, GTK_STOCK_YES,
2392 NULL) != G_ALERTALTERNATE)
2395 /* ask for confirmation before sending queued messages only
2396 in online mode and if there is at least one message queued
2397 in any of the folder queue
2399 if (prefs_common.confirm_send_queued_messages) {
2400 if (!prefs_common.work_offline) {
2401 if (alertpanel(_("Send queued messages"),
2402 _("Send all queued messages?"),
2403 GTK_STOCK_CANCEL, _("_Send"),
2404 NULL) != G_ALERTALTERNATE)
2409 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2411 alertpanel_error_log(_("Some errors occurred while "
2412 "sending queued messages."));
2414 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2415 "while sending queued messages:\n%s"), errstr);
2417 alertpanel_error_log(tmp);
2423 static void folderview_search_cb(FolderView *folderview, guint action,
2426 summary_search(folderview->summaryview);
2429 static void folderview_property_cb(FolderView *folderview, guint action,
2432 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2435 if (!folderview->selected) return;
2437 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2438 g_return_if_fail(item != NULL);
2439 g_return_if_fail(item->folder != NULL);
2441 prefs_folder_item_open(item);
2444 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2446 GSList *list = NULL;
2447 GSList *done = NULL;
2448 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2450 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2451 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2452 && list->data != node) {
2453 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2454 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2457 for (list = done; list != NULL; list = g_slist_next(list)) {
2458 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2464 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2465 FolderItem *to_folder, gboolean copy)
2467 FolderItem *from_parent = NULL;
2468 FolderItem *new_folder = NULL;
2469 GtkCTreeNode *src_node = NULL;
2473 g_return_if_fail(folderview != NULL);
2474 g_return_if_fail(from_folder != NULL);
2475 g_return_if_fail(to_folder != NULL);
2477 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2478 from_parent = folder_item_parent(from_folder);
2480 if (prefs_common.warn_dnd) {
2481 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2482 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2483 from_folder->name, to_folder->name);
2484 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2485 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2486 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2489 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2491 else if (status & G_ALERTDISABLE)
2492 prefs_common.warn_dnd = FALSE;
2495 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2496 from_folder->name, to_folder->name);
2497 STATUSBAR_PUSH(folderview->mainwin, buf);
2499 summary_clear_all(folderview->summaryview);
2500 folderview->opened = NULL;
2501 folderview->selected = NULL;
2502 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2504 main_window_cursor_wait(folderview->mainwin);
2506 statusbar_verbosity_set(FALSE);
2507 folder_item_update_freeze();
2508 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2509 statusbar_verbosity_set(FALSE);
2510 main_window_cursor_normal(folderview->mainwin);
2511 STATUSBAR_POP(folderview->mainwin);
2512 folder_item_update_thaw();
2513 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2515 folderview_sort_folders(folderview,
2516 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2517 NULL, to_folder), new_folder->folder);
2518 folderview_select(folderview, new_folder);
2520 statusbar_verbosity_set(FALSE);
2521 main_window_cursor_normal(folderview->mainwin);
2522 STATUSBAR_POP(folderview->mainwin);
2523 folder_item_update_thaw();
2525 case F_MOVE_FAILED_DEST_IS_PARENT:
2526 alertpanel_error(_("Source and destination are the same."));
2528 case F_MOVE_FAILED_DEST_IS_CHILD:
2529 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2530 _("Can't move a folder to one of its children."));
2532 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2533 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2536 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2541 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2544 static gint folderview_clist_compare(GtkCList *clist,
2545 gconstpointer ptr1, gconstpointer ptr2)
2547 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2548 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2550 if (item1->order > 0 && item2->order > 0) // if we have an order item, use it
2552 return item1->order - item2->order;
2555 // if only one folder has an order it comes first
2556 if (item1->order > 0)
2560 if (item2->order > 0)
2566 return (item2->name != NULL);
2570 return g_utf8_collate(item1->name, item2->name);
2573 static void folderview_processing_cb(FolderView *folderview, guint action,
2576 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2580 if (!folderview->selected) return;
2582 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2583 g_return_if_fail(item != NULL);
2584 g_return_if_fail(item->folder != NULL);
2586 id = folder_item_get_identifier(item);
2587 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2590 prefs_filtering_open(&item->prefs->processing, title,
2591 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2595 void folderview_set_target_folder_color(gint color_op)
2599 FolderView *folderview;
2601 for (list = folderview_list; list != NULL; list = list->next) {
2602 folderview = (FolderView *)list->data;
2603 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2605 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2606 folderview->color_op;
2612 static gchar *last_font = NULL;
2613 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2621 void folderview_reflect_prefs(void)
2623 gboolean update_font = TRUE;
2624 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2625 FolderItem *item = folderview_get_selected_item(folderview);
2626 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2627 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2628 gint height = pos->value;
2630 if (last_font && !strcmp(last_font, NORMAL_FONT))
2631 update_font = FALSE;
2634 last_font = g_strdup(NORMAL_FONT);
2637 normal_style = normal_color_style = bold_style =
2638 bold_color_style = bold_tgtfold_style = NULL;
2640 folderview_init(folderview);
2642 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2643 folderview_column_set_titles(folderview);
2644 folderview_set_all();
2646 g_signal_handlers_block_by_func
2647 (G_OBJECT(folderview->ctree),
2648 G_CALLBACK(folderview_selected), folderview);
2651 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2652 GTK_CTREE(folderview->ctree), NULL, item);
2654 folderview_select(folderview, item);
2655 folderview->open_folder = FALSE;
2656 folderview->selected = node;
2659 g_signal_handlers_unblock_by_func
2660 (G_OBJECT(folderview->ctree),
2661 G_CALLBACK(folderview_selected), folderview);
2663 pos = gtk_scrolled_window_get_vadjustment(
2664 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2665 gtk_adjustment_set_value(pos, height);
2666 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2669 static void drag_state_stop(FolderView *folderview)
2671 if (folderview->drag_timer)
2672 g_source_remove(folderview->drag_timer);
2673 folderview->drag_timer = 0;
2674 folderview->drag_node = NULL;
2677 static gint folderview_defer_expand(FolderView *folderview)
2679 if (folderview->drag_node) {
2680 folderview_recollapse_nodes(folderview, folderview->drag_node);
2681 if (folderview->drag_item->collapsed) {
2682 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2683 folderview->nodes_to_recollapse = g_slist_append
2684 (folderview->nodes_to_recollapse, folderview->drag_node);
2687 folderview->drag_item = NULL;
2688 folderview->drag_timer = 0;
2692 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2694 /* the idea is that we call drag_state_start() whenever we want expansion to
2695 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2696 * we need to call drag_state_stop() */
2697 drag_state_stop(folderview);
2698 /* request expansion */
2699 if (0 != (folderview->drag_timer = g_timeout_add
2700 (prefs_common.hover_timeout,
2701 (GtkFunction)folderview_defer_expand,
2703 folderview->drag_node = node;
2704 folderview->drag_item = item;
2708 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2709 FolderView *folderview)
2711 GdkDragContext *context;
2713 g_return_if_fail(folderview != NULL);
2714 if (folderview->selected == NULL) return;
2715 if (folderview->nodes_to_recollapse)
2716 g_slist_free(folderview->nodes_to_recollapse);
2717 folderview->nodes_to_recollapse = NULL;
2718 context = gtk_drag_begin(widget, folderview->target_list,
2719 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2720 gtk_drag_set_icon_default(context);
2723 static void folderview_drag_data_get(GtkWidget *widget,
2724 GdkDragContext *drag_context,
2725 GtkSelectionData *selection_data,
2728 FolderView *folderview)
2732 gchar *source = NULL;
2733 if (info == TARGET_DUMMY) {
2734 for (cur = GTK_CLIST(folderview->ctree)->selection;
2735 cur != NULL; cur = cur->next) {
2736 item = gtk_ctree_node_get_row_data
2737 (GTK_CTREE(folderview->ctree),
2738 GTK_CTREE_NODE(cur->data));
2740 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2741 gtk_selection_data_set(selection_data,
2742 selection_data->target, 8,
2743 source, strlen(source));
2749 g_warning("unknown info %d\n", info);
2753 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2755 FolderUpdateData *hookdata;
2756 FolderView *folderview;
2760 folderview = (FolderView *) userdata;
2761 g_return_val_if_fail(hookdata != NULL, FALSE);
2762 g_return_val_if_fail(folderview != NULL, FALSE);
2764 ctree = folderview->ctree;
2765 g_return_val_if_fail(ctree != NULL, FALSE);
2767 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2768 folderview_create_folder_node(folderview, hookdata->item);
2769 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2770 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2771 NULL, folder_item_parent(hookdata->item));
2772 folderview_sort_folders(folderview, node, hookdata->folder);
2773 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2776 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2778 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2779 if (folderview->selected == node)
2780 folderview->selected = NULL;
2781 if (folderview->opened == node)
2782 folderview->opened = NULL;
2784 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2785 folderview_set(folderview);
2790 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2791 GdkDragContext *context,
2795 FolderView *folderview)
2798 FolderItem *item = NULL, *src_item = NULL;
2799 GtkCTreeNode *node = NULL;
2800 gboolean acceptable = FALSE;
2801 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2802 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2803 int height = (int)pos->page_size;
2804 int total_height = (int)pos->upper;
2805 int vpos = (int) pos->value;
2807 if (gtk_clist_get_selection_info
2808 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2809 GtkWidget *srcwidget;
2811 if (y > height - 24 && height + vpos < total_height)
2812 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2814 if (y < 48 && y > 0)
2815 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2817 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2818 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2819 src_item = folderview->summaryview->folder_item;
2821 srcwidget = gtk_drag_get_source_widget(context);
2822 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2823 /* comes from summaryview */
2824 /* we are copying messages, so only accept folder items that are not
2825 the source item, are no root items and can copy messages */
2826 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2827 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2828 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2830 } else if (srcwidget == folderview->ctree) {
2831 /* comes from folderview */
2832 /* we are moving folder items, only accept folders that are not
2833 the source items and can copy messages and create folder items */
2834 if (item && item->folder && src_item && src_item != item &&
2835 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2836 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2837 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2838 || item->folder == src_item->folder))
2841 /* comes from another app */
2842 /* we are adding messages, so only accept folder items that are
2843 no root items and can copy messages */
2844 if (item && item->folder && folder_item_parent(item) != NULL
2845 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2846 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2851 if (acceptable || (src_item && src_item == item))
2852 drag_state_start(folderview, node, item);
2855 g_signal_handlers_block_by_func
2857 G_CALLBACK(folderview_selected), folderview);
2858 gtk_ctree_select(GTK_CTREE(widget), node);
2859 g_signal_handlers_unblock_by_func
2861 G_CALLBACK(folderview_selected), folderview);
2862 gdk_drag_status(context,
2863 (context->actions == GDK_ACTION_COPY ?
2864 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2866 if (folderview->opened)
2867 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2868 gdk_drag_status(context, 0, time);
2874 static void folderview_drag_leave_cb(GtkWidget *widget,
2875 GdkDragContext *context,
2877 FolderView *folderview)
2879 drag_state_stop(folderview);
2880 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2883 static void free_info (gpointer stuff, gpointer data)
2888 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2889 guint time, FolderItem *item)
2892 GSList *msglist = NULL;
2893 list = uri_list_extract_filenames(data);
2894 if (!(item && item->folder && folder_item_parent(item) != NULL
2895 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2897 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2898 debug_print("item doesn't fit\n");
2902 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2903 debug_print("list is empty\n");
2906 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2907 MsgFileInfo *info = NULL;
2909 if (file_is_email((gchar *)tmp->data)) {
2910 info = g_new0(MsgFileInfo, 1);
2911 info->msginfo = NULL;
2912 info->file = (gchar *)tmp->data;
2913 msglist = g_slist_prepend(msglist, info);
2914 debug_print("file is a mail\n");
2916 debug_print("file isn't a mail\n");
2920 msglist = g_slist_reverse(msglist);
2921 folder_item_add_msgs(item, msglist, FALSE);
2922 g_slist_foreach(msglist, free_info, NULL);
2923 g_slist_free(msglist);
2924 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2926 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2928 list_free_strings(list);
2932 static void folderview_drag_received_cb(GtkWidget *widget,
2933 GdkDragContext *drag_context,
2936 GtkSelectionData *data,
2939 FolderView *folderview)
2942 FolderItem *item = NULL, *src_item;
2945 if (info == TARGET_DUMMY) {
2946 drag_state_stop(folderview);
2947 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2948 /* comes from summaryview */
2949 if (gtk_clist_get_selection_info
2950 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2953 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2954 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2955 src_item = folderview->summaryview->folder_item;
2957 /* re-check (due to acceptable possibly set for folder moves */
2958 if (!(item && item->folder && item->path && !item->no_select &&
2959 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2962 if (item && src_item) {
2963 switch (drag_context->action) {
2964 case GDK_ACTION_COPY:
2965 summary_copy_selected_to(folderview->summaryview, item);
2966 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2968 case GDK_ACTION_MOVE:
2969 case GDK_ACTION_DEFAULT:
2971 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2972 summary_copy_selected_to(folderview->summaryview, item);
2974 summary_move_selected_to(folderview->summaryview, item);
2975 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2978 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2980 /* comes from folderview */
2982 gboolean folder_is_normal = TRUE;
2983 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2985 source = data->data + 17;
2986 if (gtk_clist_get_selection_info
2987 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2989 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2992 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2993 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2994 src_item = folder_find_item_from_identifier(source);
2998 src_item->stype == F_NORMAL &&
2999 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
3000 !folder_has_parent_of_type(src_item, F_DRAFT) &&
3001 !folder_has_parent_of_type(src_item, F_QUEUE) &&
3002 !folder_has_parent_of_type(src_item, F_TRASH);
3003 if (!item || item->no_select || !src_item
3004 || !folder_is_normal) {
3005 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3009 folderview_move_folder(folderview, src_item, item, copy);
3010 gtk_drag_finish(drag_context, TRUE, TRUE, time);
3012 folderview->nodes_to_recollapse = NULL;
3013 } else if (info == TARGET_MAIL_URI_LIST) {
3014 if (gtk_clist_get_selection_info
3015 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
3018 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
3020 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3021 debug_print("no node\n");
3024 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
3026 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3027 debug_print("no item\n");
3030 folderview_finish_dnd(data->data, drag_context, time, item);
3034 static void folderview_drag_end_cb(GtkWidget *widget,
3035 GdkDragContext *drag_context,
3036 FolderView *folderview)
3038 drag_state_stop(folderview);
3039 g_slist_free(folderview->nodes_to_recollapse);
3040 folderview->nodes_to_recollapse = NULL;
3043 void folderview_register_popup(FolderViewPopup *fpopup)
3047 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3048 FolderView *folderview = folderviews->data;
3049 GtkItemFactory *factory;
3051 factory = create_ifactory(folderview, fpopup);
3052 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
3054 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
3057 void folderview_unregister_popup(FolderViewPopup *fpopup)
3061 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3062 FolderView *folderview = folderviews->data;
3064 g_hash_table_remove(folderview->popups, fpopup->klass);
3066 g_hash_table_remove(folderview_popups, fpopup->klass);