2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 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>
31 #include "mainwindow.h"
32 #include "folderview.h"
33 #include "summaryview.h"
34 #include "summary_search.h"
35 #include "inputdialog.h"
36 #include "manage_window.h"
37 #include "alertpanel.h"
39 #include "stock_pixmap.h"
43 #include "prefs_common.h"
44 #include "prefs_account.h"
45 #include "prefs_filtering.h"
46 #include "prefs_folder_item.h"
49 #include "foldersel.h"
51 #include "statusbar.h"
53 #include "folderutils.h"
54 #include "partial_download.h"
55 #include "prefs_folder_column.h"
56 #include "filtering.h"
57 #include "quicksearch.h"
62 #define COL_FOLDER_WIDTH 150
63 #define COL_NUM_WIDTH 32
65 static GList *folderview_list = NULL;
67 static GtkStyle *normal_style;
68 static GtkStyle *normal_color_style;
69 static GtkStyle *bold_style;
70 static GtkStyle *bold_color_style;
71 static GtkStyle *bold_tgtfold_style;
73 static GdkPixbuf *inboxxpm;
74 static GdkPixbuf *inboxhrmxpm;
75 static GdkPixbuf *inboxopenxpm;
76 static GdkPixbuf *inboxopenhrmxpm;
77 static GdkPixbuf *outboxxpm;
78 static GdkPixbuf *outboxhrmxpm;
79 static GdkPixbuf *outboxopenxpm;
80 static GdkPixbuf *outboxopenhrmxpm;
81 static GdkPixbuf *folderxpm;
82 static GdkPixbuf *folderhrmxpm;
83 static GdkPixbuf *folderopenxpm;
84 static GdkPixbuf *folderopenhrmxpm;
85 static GdkPixbuf *trashopenxpm;
86 static GdkPixbuf *trashopenhrmxpm;
87 static GdkPixbuf *trashxpm;
88 static GdkPixbuf *trashhrmxpm;
89 static GdkPixbuf *queuexpm;
90 static GdkPixbuf *queuehrmxpm;
91 static GdkPixbuf *queueopenxpm;
92 static GdkPixbuf *queueopenhrmxpm;
93 static GdkPixbuf *draftsxpm;
94 static GdkPixbuf *draftsopenxpm;
95 static GdkPixbuf *noselectxpm;
97 static GdkPixbuf *m_inboxxpm;
98 static GdkPixbuf *m_inboxhrmxpm;
99 static GdkPixbuf *m_inboxopenxpm;
100 static GdkPixbuf *m_inboxopenhrmxpm;
101 static GdkPixbuf *m_outboxxpm;
102 static GdkPixbuf *m_outboxhrmxpm;
103 static GdkPixbuf *m_outboxopenxpm;
104 static GdkPixbuf *m_outboxopenhrmxpm;
105 static GdkPixbuf *m_folderxpm;
106 static GdkPixbuf *m_folderhrmxpm;
107 static GdkPixbuf *m_folderopenxpm;
108 static GdkPixbuf *m_folderopenhrmxpm;
109 static GdkPixbuf *m_trashopenxpm;
110 static GdkPixbuf *m_trashopenhrmxpm;
111 static GdkPixbuf *m_trashxpm;
112 static GdkPixbuf *m_trashhrmxpm;
113 static GdkPixbuf *m_queuexpm;
114 static GdkPixbuf *m_queuehrmxpm;
115 static GdkPixbuf *m_queueopenxpm;
116 static GdkPixbuf *m_queueopenhrmxpm;
117 static GdkPixbuf *m_draftsxpm;
118 static GdkPixbuf *m_draftsopenxpm;
120 static GdkPixbuf *newxpm;
121 static GdkPixbuf *unreadxpm;
122 static GdkPixbuf *readxpm;
124 static void folderview_select_node (FolderView *folderview,
125 GtkCMCTreeNode *node);
126 static void folderview_set_folders (FolderView *folderview);
127 static void folderview_sort_folders (FolderView *folderview,
128 GtkCMCTreeNode *root,
130 static void folderview_append_folder (FolderView *folderview,
132 static void folderview_update_node (FolderView *folderview,
133 GtkCMCTreeNode *node);
135 static gint folderview_clist_compare (GtkCMCList *clist,
139 /* callback functions */
140 static gboolean folderview_button_pressed (GtkWidget *ctree,
141 GdkEventButton *event,
142 FolderView *folderview);
143 static gboolean folderview_button_released (GtkWidget *ctree,
144 GdkEventButton *event,
145 FolderView *folderview);
146 static gboolean folderview_key_pressed (GtkWidget *widget,
148 FolderView *folderview);
149 static void folderview_selected (GtkCMCTree *ctree,
152 FolderView *folderview);
153 static void folderview_tree_expanded (GtkCMCTree *ctree,
154 GtkCMCTreeNode *node,
155 FolderView *folderview);
156 static void folderview_tree_collapsed (GtkCMCTree *ctree,
157 GtkCMCTreeNode *node,
158 FolderView *folderview);
159 static void folderview_popup_close (GtkMenuShell *menu_shell,
160 FolderView *folderview);
161 static void folderview_col_resized (GtkCMCList *clist,
164 FolderView *folderview);
166 static void mark_all_read_cb (GtkAction *action,
169 static void folderview_empty_trash_cb (GtkAction *action,
172 static void folderview_send_queue_cb (GtkAction *action,
175 static void folderview_search_cb (GtkAction *action,
177 static void folderview_run_processing_cb(GtkAction *action,
180 static void folderview_property_cb (GtkAction *action,
183 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
184 GdkDragContext *context,
188 FolderView *folderview);
189 static void folderview_drag_leave_cb (GtkWidget *widget,
190 GdkDragContext *context,
192 FolderView *folderview);
193 static void folderview_drag_received_cb (GtkWidget *widget,
194 GdkDragContext *drag_context,
197 GtkSelectionData *data,
200 FolderView *folderview);
202 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
203 FolderView *folderview);
205 static void folderview_drag_data_get (GtkWidget *widget,
206 GdkDragContext *drag_context,
207 GtkSelectionData *selection_data,
210 FolderView *folderview);
211 static void folderview_drag_end_cb (GtkWidget *widget,
212 GdkDragContext *drag_context,
213 FolderView *folderview);
215 static void folderview_create_folder_node (FolderView *folderview,
217 static gboolean folderview_update_folder (gpointer source,
219 static gboolean folderview_update_item_claws (gpointer source,
221 static void folderview_processing_cb(GtkAction *action, gpointer data);
222 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
223 GdkEventButton *event);
225 GHashTable *folderview_popups;
227 static GtkActionEntry folderview_common_popup_entries[] =
229 {"FolderViewPopup", NULL, "FolderViewPopup" },
230 {"FolderViewPopup/MarkAllRead", NULL, N_("Mark all re_ad"), NULL, NULL, G_CALLBACK(mark_all_read_cb) },
231 {"FolderViewPopup/---", NULL, "---" },
232 {"FolderViewPopup/RunProcessing", NULL, N_("R_un processing rules"), NULL, NULL, G_CALLBACK(folderview_run_processing_cb) },
233 {"FolderViewPopup/SearchFolder", NULL, N_("_Search folder..."), NULL, NULL, G_CALLBACK(folderview_search_cb) },
234 {"FolderViewPopup/Properties", NULL, N_("_Properties..."), NULL, NULL, G_CALLBACK(folderview_property_cb) },
235 {"FolderViewPopup/Processing", NULL, N_("Process_ing..."), NULL, NULL, G_CALLBACK(folderview_processing_cb) },
236 {"FolderViewPopup/EmptyTrash", NULL, N_("Empty _trash..."), NULL, NULL, G_CALLBACK(folderview_empty_trash_cb) },
237 {"FolderViewPopup/SendQueue", NULL, N_("Send _queue..."), NULL, NULL, G_CALLBACK(folderview_send_queue_cb) },
241 GtkTargetEntry folderview_drag_types[] =
243 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
244 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
247 void folderview_initialize(void)
249 FolderViewPopup *fpopup;
251 fpopup = g_new0(FolderViewPopup, 1);
253 fpopup->klass = "common";
254 fpopup->path = "<CommonFolder>";
255 fpopup->entries = folderview_common_popup_entries;
256 fpopup->n_entries = G_N_ELEMENTS(folderview_common_popup_entries);
257 fpopup->set_sensitivity = NULL;
259 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
260 g_hash_table_insert(folderview_popups, "common", fpopup);
263 static GtkActionGroup *create_action_group(FolderView *folderview, FolderViewPopup *fpopup)
265 FolderViewPopup *fpopup_common;
266 GtkActionGroup *action_group;
268 action_group = cm_menu_create_action_group(
270 fpopup->entries, fpopup->n_entries,
271 (gpointer)folderview);
273 if (fpopup->toggle_entries)
274 gtk_action_group_add_toggle_actions(action_group, fpopup->toggle_entries,
275 fpopup->n_toggle_entries,
276 (gpointer)folderview);
277 if (fpopup->radio_entries)
278 gtk_action_group_add_radio_actions(action_group, fpopup->radio_entries,
279 fpopup->n_radio_entries, fpopup->radio_default,
280 G_CALLBACK(fpopup->radio_callback),
281 (gpointer)folderview);
283 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
284 if (fpopup_common != fpopup) {
285 gtk_action_group_add_actions(action_group, fpopup_common->entries,
286 fpopup_common->n_entries,
287 (gpointer)folderview);
288 if (fpopup_common->toggle_entries)
289 gtk_action_group_add_toggle_actions(action_group, fpopup_common->toggle_entries,
290 fpopup_common->n_toggle_entries,
291 (gpointer)folderview);
292 if (fpopup_common->radio_entries)
293 gtk_action_group_add_radio_actions(action_group, fpopup_common->radio_entries,
294 fpopup_common->n_radio_entries, fpopup_common->radio_default,
295 G_CALLBACK(fpopup_common->radio_callback),
296 (gpointer)folderview);
302 static void create_action_groups(gpointer key, gpointer value, gpointer data)
304 FolderView *folderview = data;
305 FolderViewPopup *fpopup = value;
306 GtkActionGroup *group;
308 group = create_action_group(folderview, fpopup);
309 g_hash_table_insert(folderview->popups, fpopup->klass, group);
312 static void folderview_column_set_titles(FolderView *folderview)
314 GtkWidget *ctree = folderview->ctree;
315 GtkWidget *label_folder;
316 GtkWidget *label_new;
317 GtkWidget *label_unread;
318 GtkWidget *label_total;
319 GtkWidget *hbox_folder;
321 GtkWidget *hbox_unread;
322 GtkWidget *hbox_total;
323 gint *col_pos = folderview->col_pos;
325 debug_print("setting titles...\n");
326 gtk_widget_realize(folderview->ctree);
327 gtk_widget_show_all(folderview->scrolledwin);
329 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
330 * instead text (text overflows making them unreadable and ugly) */
331 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_NEW,
333 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_UNREAD,
335 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_READ,
338 label_folder = gtk_label_new(_("Folder"));
339 label_new = gtk_image_new_from_pixbuf(newxpm);
340 label_unread = gtk_image_new_from_pixbuf(unreadxpm);
341 label_total = gtk_image_new_from_pixbuf(readxpm);
343 gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree));
345 hbox_folder = gtk_hbox_new(FALSE, 4);
346 hbox_new = gtk_hbox_new(FALSE, 4);
347 hbox_unread = gtk_hbox_new(FALSE, 4);
348 hbox_total = gtk_hbox_new(FALSE, 4);
351 gtk_box_pack_start(GTK_BOX(hbox_folder), label_folder, TRUE, TRUE, 0);
352 gtk_misc_set_alignment (GTK_MISC (label_folder), 0, 0.5);
353 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
354 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
355 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
356 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
357 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
358 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
360 gtk_widget_show_all(hbox_folder);
361 gtk_widget_show_all(hbox_new);
362 gtk_widget_show_all(hbox_unread);
363 gtk_widget_show_all(hbox_total);
366 gtk_widget_set_size_request(hbox_new, -1, 20);
367 gtk_widget_set_size_request(hbox_unread, -1, 20);
368 gtk_widget_set_size_request(hbox_total, -1, 20);
371 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_FOLDER],hbox_folder);
372 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_NEW],hbox_new);
373 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
374 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
380 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
381 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
382 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
385 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
387 FolderView *folderview = (FolderView *)data;
388 GdkEventButton event;
389 if (folderview_get_selected_item(folderview) == NULL)
393 event.time = gtk_get_current_event_time();
395 folderview_set_sens_and_popup_menu(folderview, -1,
402 static GtkWidget *folderview_ctree_create(FolderView *folderview)
406 FolderColumnState *col_state;
407 FolderColumnType type;
408 gchar *titles[N_FOLDER_COLS];
410 GtkWidget *scrolledwin = folderview->scrolledwin;
412 debug_print("creating tree...\n");
413 memset(titles, 0, sizeof(titles));
415 col_state = prefs_folder_column_get_config();
416 memset(titles, 0, sizeof(titles));
418 col_pos = folderview->col_pos;
420 for (i = 0; i < N_FOLDER_COLS; i++) {
421 folderview->col_state[i] = col_state[i];
422 type = col_state[i].type;
426 titles[col_pos[F_COL_FOLDER]] = _("Folder");
427 titles[col_pos[F_COL_NEW]] = _("New");
428 titles[col_pos[F_COL_UNREAD]] = _("Unread");
429 /* TRANSLATORS: This in Number sign in American style */
430 titles[col_pos[F_COL_TOTAL]] = _("#");
432 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
435 if (prefs_common.show_col_headers == FALSE)
436 gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree));
439 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
440 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[F_COL_NEW],
442 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
443 col_pos[F_COL_UNREAD],
445 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
446 col_pos[F_COL_TOTAL],
448 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
449 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
450 GTK_CMCTREE_EXPANDER_TRIANGLE);
452 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
453 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
455 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
456 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree), folderview_clist_compare);
458 /* don't let title buttons take key focus */
459 for (i = 0; i < N_FOLDER_COLS; i++) {
460 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[i].button, FALSE);
461 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[i],
462 prefs_common.folder_col_size[i]);
463 gtk_cmclist_set_column_visibility
464 (GTK_CMCLIST(ctree), i, col_state[i].visible);
467 g_signal_connect(G_OBJECT(ctree), "key_press_event",
468 G_CALLBACK(folderview_key_pressed),
470 g_signal_connect(G_OBJECT(ctree), "button_press_event",
471 G_CALLBACK(folderview_button_pressed),
473 g_signal_connect(G_OBJECT(ctree), "popup-menu",
474 G_CALLBACK(folderview_popup_menu), folderview);
475 g_signal_connect(G_OBJECT(ctree), "button_release_event",
476 G_CALLBACK(folderview_button_released),
478 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
479 G_CALLBACK(folderview_selected), folderview);
481 /* drag-n-dropping folders on maemo is impractical as this
482 * opens the folder almost everytime */
483 g_signal_connect(G_OBJECT(ctree), "start_drag",
484 G_CALLBACK(folderview_start_drag), folderview);
486 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
487 G_CALLBACK(folderview_drag_data_get),
490 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
491 G_CALLBACK(folderview_tree_expanded),
493 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
494 G_CALLBACK(folderview_tree_collapsed),
497 g_signal_connect(G_OBJECT(ctree), "resize_column",
498 G_CALLBACK(folderview_col_resized),
502 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
503 folderview_drag_types, 2,
504 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
505 g_signal_connect(G_OBJECT(ctree), "drag_motion",
506 G_CALLBACK(folderview_drag_motion_cb),
508 g_signal_connect(G_OBJECT(ctree), "drag_leave",
509 G_CALLBACK(folderview_drag_leave_cb),
511 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
512 G_CALLBACK(folderview_drag_received_cb),
514 g_signal_connect(G_OBJECT(ctree), "drag_end",
515 G_CALLBACK(folderview_drag_end_cb),
518 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
523 void folderview_set_column_order(FolderView *folderview)
525 GtkWidget *ctree = folderview->ctree;
526 FolderItem *item = folderview_get_selected_item(folderview);
527 FolderItem *sel_item = NULL, *op_item = NULL;
528 GtkWidget *scrolledwin = folderview->scrolledwin;
530 if (folderview->drag_timer_id != 0) {
531 g_source_remove(folderview->drag_timer_id);
532 folderview->drag_timer_id = 0;
534 if (folderview->deferred_refresh_id != 0) {
535 g_source_remove(folderview->deferred_refresh_id);
536 folderview->deferred_refresh_id = 0;
538 if (folderview->scroll_timeout_id != 0) {
539 g_source_remove(folderview->scroll_timeout_id);
540 folderview->scroll_timeout_id = 0;
542 if (folderview->postpone_select_id != 0) {
543 g_source_remove(folderview->postpone_select_id);
544 folderview->postpone_select_id = 0;
547 if (folderview->selected)
548 sel_item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(ctree), folderview->selected);
549 if (folderview->opened)
550 op_item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(ctree), folderview->opened);
552 debug_print("recreating tree...\n");
553 gtk_widget_destroy(folderview->ctree);
556 folderview->ctree = ctree = folderview_ctree_create(folderview);
557 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
558 GTK_CMCLIST(ctree)->hadjustment);
559 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
560 GTK_CMCLIST(ctree)->vadjustment);
561 gtk_widget_show(ctree);
564 folderview->selected = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, sel_item);
566 folderview->opened = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, op_item);
568 folderview_set(folderview);
569 folderview_column_set_titles(folderview);
571 folderview_select(folderview,item);
574 FolderView *folderview_create(void)
576 FolderView *folderview;
577 GtkWidget *scrolledwin;
580 debug_print("Creating folder view...\n");
581 folderview = g_new0(FolderView, 1);
583 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
584 gtk_scrolled_window_set_policy
585 (GTK_SCROLLED_WINDOW(scrolledwin),
586 GTK_POLICY_AUTOMATIC,
587 prefs_common.folderview_vscrollbar_policy);
588 gtk_widget_set_size_request(scrolledwin,
589 prefs_common.folderview_width,
590 prefs_common.folderview_height);
592 folderview->scrolledwin = scrolledwin;
593 ctree = folderview_ctree_create(folderview);
595 /* create popup factories */
596 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
597 g_hash_table_foreach(folderview_popups, create_action_groups, folderview);
599 folderview->ctree = ctree;
601 folderview->folder_update_callback_id =
602 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
603 folderview->folder_item_update_callback_id =
604 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
606 gtk_widget_show_all(scrolledwin);
608 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
609 folderview_list = g_list_append(folderview_list, folderview);
611 folderview->drag_timer_id = 0;
612 folderview->deferred_refresh_id = 0;
613 folderview->scroll_timeout_id = 0;
614 folderview->postpone_select_id = 0;
619 void folderview_init(FolderView *folderview)
621 GtkWidget *ctree = folderview->ctree;
624 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm);
625 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm);
626 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm);
627 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm);
628 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm);
629 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm);
630 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm);
631 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm);
632 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
633 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm);
634 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
635 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm);
636 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm);
637 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm);
638 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm);
639 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm);
640 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm);
641 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm);
642 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm);
643 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm);
644 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm);
645 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm);
646 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm);
648 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm);
649 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm);
650 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm);
651 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm);
652 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm);
653 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm);
654 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm);
655 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm);
656 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm);
657 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm);
658 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm);
659 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm);
660 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm);
661 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm);
662 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm);
663 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm);
664 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm);
665 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm);
666 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm);
667 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm);
668 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm);
669 stock_pixbuf_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm);
672 PangoFontDescription *font_desc;
673 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
674 font_desc = pango_font_description_from_string(NORMAL_FONT);
676 if (normal_style->font_desc)
677 pango_font_description_free
678 (normal_style->font_desc);
679 normal_style->font_desc = font_desc;
681 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
682 normal_color_style = gtk_style_copy(normal_style);
683 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
685 gtk_widget_set_style(ctree, normal_style);
689 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
690 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
691 if (prefs_common.derive_from_normal_font || !BOLD_FONT) {
692 pango_font_description_set_weight
693 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
695 PangoFontDescription *font_desc;
696 font_desc = pango_font_description_from_string(BOLD_FONT);
698 if (bold_style->font_desc)
699 pango_font_description_free
700 (bold_style->font_desc);
701 bold_style->font_desc = font_desc;
704 bold_color_style = gtk_style_copy(bold_style);
705 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
707 bold_tgtfold_style = gtk_style_copy(bold_style);
708 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
712 static gboolean folderview_defer_set(gpointer data)
714 FolderView *folderview = (FolderView *)data;
715 MainWindow *mainwin = folderview->mainwin;
719 if (mainwin->lock_count)
722 debug_print("doing deferred folderview_set now\n");
723 folderview_set(folderview);
725 folderview->deferred_refresh_id = 0;
729 void folderview_set(FolderView *folderview)
731 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
732 MainWindow *mainwin = folderview->mainwin;
733 FolderItem *sel_item = NULL, *op_item = NULL;
738 if (mainwin->lock_count) {
739 if (folderview->deferred_refresh_id == 0)
740 folderview->deferred_refresh_id =
741 g_timeout_add(500, folderview_defer_set, folderview);
742 debug_print("deferred folderview_set\n");
747 debug_print("Setting folder info...\n");
748 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
750 main_window_cursor_wait(mainwin);
752 if (folderview->selected)
753 sel_item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
754 if (folderview->opened)
755 op_item = gtk_cmctree_node_get_row_data(ctree, folderview->opened);
757 folderview->selected = NULL;
758 folderview->opened = NULL;
760 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
761 gtk_cmclist_clear(GTK_CMCLIST(ctree));
763 folderview_set_folders(folderview);
766 folderview->selected = gtk_cmctree_find_by_row_data(ctree, NULL, sel_item);
768 folderview->opened = gtk_cmctree_find_by_row_data(ctree, NULL, op_item);
770 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
771 main_window_cursor_normal(mainwin);
772 STATUSBAR_POP(mainwin);
776 void folderview_set_all(void)
780 for (list = folderview_list; list != NULL; list = list->next)
781 folderview_set((FolderView *)list->data);
784 void folderview_select(FolderView *folderview, FolderItem *item)
786 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
787 GtkCMCTreeNode *node;
788 GtkCMCTreeNode *old_selected = folderview->selected;
792 node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
793 if (node) folderview_select_node(folderview, node);
795 if (old_selected != node)
796 folder_update_op_count();
799 static void mark_all_read_cb(GtkAction *action, gpointer data)
801 FolderView *folderview = (FolderView *)data;
805 item = folderview_get_selected_item(folderview);
809 if (folderview->summaryview->folder_item != item
810 && prefs_common.ask_mark_all_read) {
811 val = alertpanel_full(_("Mark all as read"),
812 _("Do you really want to mark all mails in this "
813 "folder as read?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
814 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
816 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
818 else if (val & G_ALERTDISABLE)
819 prefs_common.ask_mark_all_read = FALSE;
823 folder_item_update_freeze();
824 if (folderview->summaryview->folder_item != item)
825 summary_lock(folderview->summaryview);
827 summary_freeze(folderview->summaryview);
829 folderutils_mark_all_read(item);
831 if (folderview->summaryview->folder_item != item)
832 summary_unlock(folderview->summaryview);
834 summary_thaw(folderview->summaryview);
835 folder_item_update_thaw();
838 static void folderview_select_node(FolderView *folderview, GtkCMCTreeNode *node)
840 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
842 cm_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_cmctree_select(ctree, node);
851 if ((folderview->summaryview->folder_item &&
852 folderview->summaryview->folder_item->total_msgs > 0) ||
853 prefs_common.layout_mode == SMALL_LAYOUT)
854 summary_grab_focus(folderview->summaryview);
856 gtk_widget_grab_focus(folderview->ctree);
858 gtkut_ctree_expand_parent_all(ctree, node);
861 void folderview_unselect(FolderView *folderview)
863 if (folderview->opened && !GTK_CMCTREE_ROW(folderview->opened)->children)
865 (GTK_CMCTREE(folderview->ctree), folderview->opened);
867 folderview->selected = folderview->opened = NULL;
870 static GtkCMCTreeNode *folderview_find_next_with_flag(GtkCMCTree *ctree,
871 GtkCMCTreeNode *node,
877 node = gtkut_ctree_node_next(ctree, node);
879 node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
881 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
882 item = gtk_cmctree_node_get_row_data(ctree, node);
883 if (item->stype == F_TRASH || item->stype == F_DRAFT)
887 if(item->unread_msgs > 0)
891 if(item->new_msgs > 0)
895 if(item->marked_msgs > 0)
904 void folderview_select_next_with_flag(FolderView *folderview,
908 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
909 GtkCMCTreeNode *node = NULL;
910 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
911 gboolean last_open = prefs_common.always_show_msg;
915 prefs_common.summary_select_prio[0] = ACTION_UNREAD;
918 prefs_common.summary_select_prio[0] = ACTION_NEW;
921 prefs_common.summary_select_prio[0] = ACTION_MARKED;
924 prefs_common.always_show_msg = force_open ? OPENMSG_ALWAYS : last_open;
926 node = folderview_find_next_with_flag(ctree, folderview->opened, flag);
928 folderview_select_node(folderview, node);
932 if (!folderview->opened ||
933 folderview->opened == GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list)) {
937 /* search again from the first node */
938 node = folderview_find_next_with_flag(ctree, NULL, flag);
940 folderview_select_node(folderview, node);
943 prefs_common.summary_select_prio[0] = last_summary_select_prio;
944 prefs_common.always_show_msg = last_open;
947 FolderItem *folderview_get_selected_item(FolderView *folderview)
949 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
951 if (!folderview->selected) return NULL;
952 return gtk_cmctree_node_get_row_data(ctree, folderview->selected);
955 static void folderview_set_folders(FolderView *folderview)
958 list = folder_get_list();
960 for (; list != NULL; list = list->next) {
961 folderview_append_folder(folderview, FOLDER(list->data));
965 static gchar *get_scan_str(FolderItem *item)
968 return g_strdup_printf(_("Scanning folder %s%c%s..."),
969 item->folder->name, G_DIR_SEPARATOR,
972 return g_strdup_printf(_("Scanning folder %s..."),
975 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
979 for (list = folderview_list; list != NULL; list = list->next) {
980 FolderView *folderview = (FolderView *)list->data;
981 MainWindow *mainwin = folderview->mainwin;
982 gchar *str = get_scan_str(item);
984 STATUSBAR_PUSH(mainwin, str);
985 STATUSBAR_POP(mainwin);
990 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
993 MainWindow *mainwin = mainwindow_get_mainwindow();
994 FolderView *folderview = NULL;
995 GtkAdjustment *pos = NULL;
998 cm_return_if_fail(folder != NULL);
1000 if (!folder->klass->scan_tree) return;
1003 alertpanel_full(_("Rebuild folder tree"),
1004 _("Rebuilding the folder tree will remove "
1005 "local caches. Do you want to continue?"),
1006 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1007 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1008 != G_ALERTALTERNATE) {
1014 window = label_window_create(_("Rebuilding folder tree..."));
1016 window = label_window_create(_("Scanning folder tree..."));
1019 folderview = mainwin->folderview;
1022 pos = gtk_scrolled_window_get_vadjustment(
1023 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1024 height = gtk_adjustment_get_value(pos);
1027 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1028 folder_scan_tree(folder, rebuild);
1029 folder_set_ui_func(folder, NULL, NULL);
1031 folderview_set_all();
1034 pos = gtk_scrolled_window_get_vadjustment(
1035 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1036 gtk_adjustment_set_value(pos, height);
1037 gtk_adjustment_changed(pos);
1039 label_window_destroy(window);
1043 /** folderview_check_new()
1044 * Scan and update the folder and return the
1045 * count the number of new messages since last check.
1046 * \param folder the folder to check for new messages
1047 * \return the number of new messages since last check
1049 gint folderview_check_new(Folder *folder)
1053 FolderView *folderview;
1055 GtkCMCTreeNode *node;
1057 gint former_new_msgs = 0;
1058 gint former_new = 0, former_unread = 0, former_total;
1060 for (list = folderview_list; list != NULL; list = list->next) {
1061 folderview = (FolderView *)list->data;
1062 ctree = GTK_CMCTREE(folderview->ctree);
1063 folderview->scanning_folder = folder;
1065 main_window_lock(folderview->mainwin);
1067 for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
1068 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1070 item = gtk_cmctree_node_get_row_data(ctree, node);
1071 if (!item || !item->path || !item->folder) continue;
1072 if (item->no_select) continue;
1073 if (folder && folder != item->folder) continue;
1074 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1075 if (!item->prefs->newmailcheck) continue;
1076 if (item->processing_pending == TRUE) {
1077 debug_print("skipping %s, processing pending\n",
1078 item->path ? item->path : item->name);
1081 if (item->scanning != ITEM_NOT_SCANNING) {
1082 debug_print("skipping %s, scanning\n",
1083 item->path ? item->path : item->name);
1087 str = get_scan_str(item);
1089 STATUSBAR_PUSH(folderview->mainwin, str);
1093 folderview_scan_tree_func(item->folder, item, NULL);
1094 former_new = item->new_msgs;
1095 former_unread = item->unread_msgs;
1096 former_total = item->total_msgs;
1098 if (item->folder->klass->scan_required &&
1099 (item->folder->klass->scan_required(item->folder, item) ||
1100 item->folder->inbox == item ||
1101 item->opened == TRUE ||
1102 item->processing_pending == TRUE)) {
1103 if (folder_item_scan(item) < 0) {
1105 summaryview_unlock(folderview->summaryview, item);
1106 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1107 log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
1108 item->path ? item->path:item->name);
1109 STATUSBAR_POP(folderview->mainwin);
1111 } else if (!FOLDER_IS_LOCAL(folder)) {
1112 STATUSBAR_POP(folderview->mainwin);
1117 } else if (!item->folder->klass->scan_required) {
1118 if (folder_item_scan(item) < 0) {
1119 summaryview_unlock(folderview->summaryview, item);
1120 if (folder && !FOLDER_IS_LOCAL(folder)) {
1121 STATUSBAR_POP(folderview->mainwin);
1126 if (former_new != item->new_msgs ||
1127 former_unread != item->unread_msgs ||
1128 former_total != item->total_msgs)
1129 folderview_update_node(folderview, node);
1131 new_msgs += item->new_msgs;
1132 former_new_msgs += former_new;
1133 STATUSBAR_POP(folderview->mainwin);
1135 folderview->scanning_folder = NULL;
1136 main_window_unlock(folderview->mainwin);
1140 folder_write_list();
1141 /* Number of new messages since last check is the just the difference
1142 * between former_new_msgs and new_msgs. If new_msgs is less than
1143 * former_new_msgs, that would mean another session accessed the folder
1144 * and the result is not well defined.
1146 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1150 void folderview_check_new_all(void)
1154 FolderView *folderview;
1156 folderview = (FolderView *)folderview_list->data;
1159 main_window_lock(folderview->mainwin);
1160 window = label_window_create
1161 (_("Checking for new messages in all folders..."));
1163 list = folder_get_list();
1164 for (; list != NULL; list = list->next) {
1165 Folder *folder = list->data;
1167 folderview_check_new(folder);
1170 folder_write_list();
1171 folderview_set_all();
1173 label_window_destroy(window);
1174 main_window_unlock(folderview->mainwin);
1178 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1184 if (!item || !item->folder || !item->folder->node)
1187 node = item->folder->node;
1189 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1190 node = node->children;
1193 (item->new_msgs > 0 ||
1194 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1198 while (node != NULL) {
1199 if (node && node->data) {
1200 FolderItem *next_item = (FolderItem*) node->data;
1202 if (folderview_have_new_children_sub(folderview,
1211 static gboolean folderview_have_new_children(FolderView *folderview,
1214 return folderview_have_new_children_sub(folderview, item, FALSE);
1217 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1223 if (!item || !item->folder || !item->folder->node)
1226 node = item->folder->node;
1228 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1229 node = node->children;
1232 (item->unread_msgs > 0 ||
1233 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1237 while (node != NULL) {
1238 if (node && node->data) {
1239 FolderItem *next_item = (FolderItem*) node->data;
1241 if (folderview_have_unread_children_sub(folderview,
1251 static gboolean folderview_have_unread_children(FolderView *folderview,
1254 return folderview_have_unread_children_sub(folderview, item, FALSE);
1257 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1263 if (!item || !item->folder || !item->folder->node)
1266 node = item->folder->node;
1268 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1269 node = node->children;
1271 if (in_sub && item->search_match){
1275 while (node != NULL) {
1276 if (node && node->data) {
1277 FolderItem *next_item = (FolderItem*) node->data;
1279 if (folderview_have_matching_children_sub(folderview,
1289 static gboolean folderview_have_matching_children(FolderView *folderview,
1292 return folderview_have_matching_children_sub(folderview, item, FALSE);
1295 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1301 if (!item || !item->folder || !item->folder->node)
1304 node = item->folder->node;
1306 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1307 node = node->children;
1309 if (item->marked_msgs != 0) {
1313 while (node != NULL) {
1314 if (node && node->data) {
1315 FolderItem *next_item = (FolderItem*) node->data;
1317 if (folderview_have_marked_children_sub(folderview,
1326 static gboolean folderview_have_marked_children(FolderView *folderview,
1329 return folderview_have_marked_children_sub(folderview, item, FALSE);
1332 static void folderview_update_node(FolderView *folderview, GtkCMCTreeNode *node)
1334 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1335 GtkStyle *style = NULL;
1336 GtkStyle *color_style = NULL;
1338 GdkPixbuf *xpm, *openxpm;
1339 static GdkPixbuf *searchicon;
1340 gboolean mark = FALSE;
1343 gboolean add_unread_mark;
1344 gboolean add_sub_match_mark;
1345 gboolean use_bold, use_color;
1346 gint *col_pos = folderview->col_pos;
1347 SpecialFolderItemType stype;
1349 item = gtk_cmctree_node_get_row_data(ctree, node);
1350 cm_return_if_fail(item != NULL);
1352 if (!GTK_CMCTREE_ROW(node)->expanded)
1353 mark = folderview_have_marked_children(folderview, item);
1355 mark = (item->marked_msgs != 0);
1357 stype = item->stype;
1358 if (stype == F_NORMAL) {
1359 if (folder_has_parent_of_type(item, F_TRASH))
1361 else if (folder_has_parent_of_type(item, F_DRAFT))
1363 else if (folder_has_parent_of_type(item, F_OUTBOX))
1365 else if (folder_has_parent_of_type(item, F_QUEUE))
1370 if (item->hide_read_msgs || item->hide_read_threads) {
1371 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1372 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1374 xpm = mark?m_inboxxpm:inboxxpm;
1375 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1379 if (item->hide_read_msgs || item->hide_read_threads) {
1380 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1381 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1383 xpm = mark?m_outboxxpm:outboxxpm;
1384 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1388 if (item->hide_read_msgs || item->hide_read_threads) {
1389 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1390 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1392 xpm = mark?m_queuexpm:queuexpm;
1393 openxpm = mark?m_queueopenxpm:queueopenxpm;
1397 if (item->hide_read_msgs || item->hide_read_threads) {
1398 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1399 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1401 xpm = mark?m_trashxpm:trashxpm;
1402 openxpm = mark?m_trashopenxpm:trashopenxpm;
1406 xpm = mark?m_draftsxpm:draftsxpm;
1407 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1410 if (item->hide_read_msgs || item->hide_read_threads) {
1411 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1412 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1414 xpm = mark?m_folderxpm:folderxpm;
1415 openxpm = mark?m_folderopenxpm:folderopenxpm;
1419 if (item->no_select) {
1420 xpm = openxpm = noselectxpm;
1423 name = folder_item_get_name(item);
1425 if (!GTK_CMCTREE_ROW(node)->expanded) {
1426 add_unread_mark = folderview_have_unread_children(
1428 add_sub_match_mark = folderview_have_matching_children(
1431 add_unread_mark = FALSE;
1432 add_sub_match_mark = FALSE;
1435 if (item->search_match) {
1437 stock_pixbuf_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1440 xpm = openxpm = searchicon;
1444 if (prefs_common.display_folder_unread) {
1445 if (folder_has_parent_of_type(item, F_QUEUE)) {
1446 /* only total_msgs matters here */
1447 if (item->total_msgs > 0) {
1448 /* show total number (should be equal to the unread number)
1450 str = g_strdup_printf("%s (%d%s%s)",
1451 name, item->total_msgs,
1452 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1453 (item->unreadmarked_msgs > 0) ? "!" : "");
1456 if (prefs_common.display_folder_unread == 1) {
1457 if (item->unread_msgs > 0) {
1458 /* show unread number and signs */
1459 str = g_strdup_printf("%s (%d%s%s)",
1460 name, item->unread_msgs,
1461 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1462 (item->unreadmarked_msgs > 0) ? "!" : "");
1465 if (item->total_msgs > 0) {
1466 /* show unread number, total number and signs if any */
1467 str = g_strdup_printf("%s (%d/%d%s%s)",
1468 name, item->unread_msgs, item->total_msgs,
1469 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1470 (item->unreadmarked_msgs > 0) ? "!" : "");
1474 if ((str == NULL) &&
1475 (add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
1476 /* no unread/total numbers, but at least one sign */
1477 str = g_strdup_printf("%s (%s%s)",
1479 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1480 (item->unreadmarked_msgs > 0) ? "!" : "");
1484 /* last fallback, folder name only or with +! sign */
1485 if (item->unreadmarked_msgs > 0 && add_sub_match_mark) {
1486 str = g_strdup_printf("%s%s",
1488 } else if (item->unreadmarked_msgs > 0) {
1489 str = g_strdup_printf("%s%s",
1491 } else if (add_sub_match_mark) {
1492 str = g_strdup_printf("%s%s",
1495 str = g_strdup_printf("%s", name);
1498 gtk_cmctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1500 FALSE, GTK_CMCTREE_ROW(node)->expanded);
1504 if (!folder_item_parent(item)) {
1505 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1506 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1507 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1509 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW], item->new_msgs > 0 ? itos(item->new_msgs) : prefs_common.zero_replacement);
1510 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
1511 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], item->total_msgs > 0 ? itos(item->total_msgs) : prefs_common.zero_replacement);
1514 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1515 folder_has_parent_of_type(item, F_TRASH)) {
1516 use_bold = use_color = FALSE;
1517 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1518 GSList *list = folder_item_get_msg_list(item);
1520 use_bold = use_color = FALSE;
1521 for (cur = list; cur; cur = cur->next) {
1522 MsgInfo *msginfo = (MsgInfo *)cur->data;
1523 if (!MSG_IS_DELETED(msginfo->flags)) {
1524 /* highlight queue folder if there are any messages */
1525 use_bold = use_color = TRUE;
1529 procmsg_msg_list_free(list);
1531 /* if unread messages exist, print with bold font */
1532 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1534 /* if new messages exist, print with colored letter */
1536 (item->new_msgs > 0) ||
1538 folderview_have_new_children(folderview, item));
1541 gtk_cmctree_node_set_foreground(ctree, node, NULL);
1546 if (item->prefs->color > 0 && !use_color) {
1547 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1548 color_style = gtk_style_copy(bold_style);
1549 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1550 style = color_style;
1551 } else if (use_color) {
1552 style = bold_color_style;
1555 if (item->op_count > 0) {
1556 style = bold_tgtfold_style;
1558 } else if (use_color) {
1559 style = normal_color_style;
1560 gtk_cmctree_node_set_foreground(ctree, node,
1561 &folderview->color_new);
1562 } else if (item->op_count > 0) {
1563 style = bold_tgtfold_style;
1564 } else if (item->prefs->color > 0) {
1566 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1567 color_style = gtk_style_copy(normal_style);
1568 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1569 style = color_style;
1571 style = normal_style;
1574 gtk_cmctree_node_set_row_style(ctree, node, style);
1576 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1577 folderview_update_node(folderview, node);
1580 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1583 FolderView *folderview;
1585 GtkCMCTreeNode *node;
1587 cm_return_if_fail(item != NULL);
1589 for (list = folderview_list; list != NULL; list = list->next) {
1590 folderview = (FolderView *)list->data;
1591 ctree = GTK_CMCTREE(folderview->ctree);
1593 node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
1594 if (node && item->search_match != matches) {
1595 item->search_match = matches;
1596 folderview_update_node(folderview, node);
1601 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1603 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1604 FolderView *folderview = (FolderView *)data;
1606 GtkCMCTreeNode *node;
1607 cm_return_val_if_fail(update_info != NULL, TRUE);
1608 cm_return_val_if_fail(update_info->item != NULL, TRUE);
1609 cm_return_val_if_fail(folderview != NULL, FALSE);
1611 ctree = GTK_CMCTREE(folderview->ctree);
1613 node = gtk_cmctree_find_by_row_data(ctree, NULL, update_info->item);
1616 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1617 folderview_update_node(folderview, node);
1619 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
1620 update_info->item == folderview->summaryview->folder_item &&
1621 update_info->item != NULL)
1622 if (!quicksearch_has_sat_predicate(folderview->summaryview->quicksearch))
1623 summary_show(folderview->summaryview, update_info->item);
1629 static gboolean folderview_gnode_func(GtkCMCTree *ctree, guint depth,
1630 GNode *gnode, GtkCMCTreeNode *cnode,
1633 FolderView *folderview = (FolderView *)data;
1634 FolderItem *item = FOLDER_ITEM(gnode->data);
1636 cm_return_val_if_fail(item != NULL, FALSE);
1638 gtk_cmctree_node_set_row_data(ctree, cnode, item);
1639 folderview_update_node(folderview, cnode);
1644 static void folderview_expand_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1647 FolderView *folderview = (FolderView *)data;
1650 if (GTK_CMCTREE_ROW(node)->children) {
1651 item = gtk_cmctree_node_get_row_data(ctree, node);
1652 cm_return_if_fail(item != NULL);
1654 if (!item->collapsed)
1655 gtk_cmctree_expand(ctree, node);
1657 folderview_update_node(folderview, node);
1661 static void set_special_folder(GtkCMCTree *ctree, FolderItem *item,
1662 GtkCMCTreeNode *root, GtkCMCTreeNode **prev)
1665 GtkCMCTreeNode *node, *parent, *sibling;
1667 node = gtk_cmctree_find_by_row_data(ctree, root, item);
1669 g_warning("%s not found.\n", item->path);
1671 parent = GTK_CMCTREE_ROW(node)->parent;
1672 if (*prev && parent == GTK_CMCTREE_ROW(*prev)->parent)
1673 sibling = GTK_CMCTREE_ROW(*prev)->sibling;
1675 sibling = GTK_CMCTREE_ROW(parent)->children;
1679 tmp = gtk_cmctree_node_get_row_data
1681 if (tmp->stype != F_NORMAL)
1682 sibling = GTK_CMCTREE_ROW(sibling)->sibling;
1686 if (node != sibling)
1687 gtk_cmctree_move(ctree, node, parent, sibling);
1694 static void folderview_sort_folders(FolderView *folderview, GtkCMCTreeNode *root,
1697 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1698 GtkCMCTreeNode *prev = NULL;
1700 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
1701 gtk_sctree_sort_recursive(ctree, root);
1702 if (root && GTK_CMCTREE_ROW(root)->parent) {
1703 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1706 set_special_folder(ctree, folder->inbox, root, &prev);
1707 set_special_folder(ctree, folder->outbox, root, &prev);
1708 set_special_folder(ctree, folder->draft, root, &prev);
1709 set_special_folder(ctree, folder->queue, root, &prev);
1710 set_special_folder(ctree, folder->trash, root, &prev);
1711 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1714 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1716 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1717 GtkCMCTreeNode *root;
1719 cm_return_if_fail(folder != NULL);
1721 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1722 folderview_gnode_func, folderview);
1723 gtk_cmctree_pre_recursive(ctree, root, folderview_expand_func,
1725 folderview_sort_folders(folderview, root, folder);
1728 /* callback functions */
1729 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1730 GdkEventButton *event)
1734 FolderViewPopup *fpopup;
1735 GtkActionGroup *action_group;
1737 FolderItem *special_trash = NULL, *special_queue = NULL;
1739 GtkUIManager *ui_manager = gtk_ui_manager_new();
1741 if (folderview->ui_manager)
1742 g_object_unref(folderview->ui_manager);
1744 folderview->ui_manager = ui_manager;
1745 item = folderview_get_selected_item(folderview);
1747 cm_return_if_fail(item != NULL);
1748 cm_return_if_fail(item->folder != NULL);
1749 folder = item->folder;
1751 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1754 action_group = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1756 fpopup = g_hash_table_lookup(folderview_popups, "common");
1757 action_group = g_hash_table_lookup(folderview->popups, "common");
1760 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1761 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR)
1762 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU)
1764 if (fpopup->add_menuitems)
1765 fpopup->add_menuitems(ui_manager, item);
1767 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM)
1768 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1769 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM)
1770 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM)
1771 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM)
1772 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM)
1774 if (fpopup->set_sensitivity != NULL)
1775 fpopup->set_sensitivity(ui_manager, item);
1777 if (NULL != (ac = account_find_from_item(item))) {
1778 special_trash = account_get_special_folder(ac, F_TRASH);
1779 special_queue = account_get_special_folder(ac, F_QUEUE);
1782 if ((item == folder->trash || item == special_trash
1783 || folder_has_parent_of_type(item, F_TRASH))) {
1784 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1785 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM)
1788 if ((item == folder->queue || item == special_queue
1789 || folder_has_parent_of_type(item, F_QUEUE))) {
1790 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1791 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM)
1794 #define SET_SENS(name, sens) \
1795 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1797 SET_SENS("FolderViewPopup/MarkAllRead", item->unread_msgs >= 1);
1798 SET_SENS("FolderViewPopup/SearchFolder", item->total_msgs >= 1 &&
1799 folderview->selected == folderview->opened);
1800 SET_SENS("FolderViewPopup/Properties", TRUE);
1802 SET_SENS("FolderViewPopup/RunProcessing", item->prefs->processing &&
1803 item->total_msgs >= 1 && !item->processing_pending);
1804 SET_SENS("FolderViewPopup/Processing", item->node->parent != NULL &&
1805 !item->no_select && !item->processing_pending);
1807 if (item == folder->trash || item == special_trash
1808 || folder_has_parent_of_type(item, F_TRASH)) {
1809 GSList *msglist = folder_item_get_msg_list(item);
1810 SET_SENS("FolderViewPopup/EmptyTrash", msglist != NULL);
1811 procmsg_msg_list_free(msglist);
1813 if (item == folder->queue || item == special_queue
1814 || folder_has_parent_of_type(item, F_QUEUE)) {
1815 GSList *msglist = folder_item_get_msg_list(item);
1816 SET_SENS("FolderViewPopup/SendQueue", msglist != NULL);
1817 procmsg_msg_list_free(msglist);
1821 popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1822 gtk_ui_manager_get_widget(ui_manager, "/Popup/FolderViewPopup")) );
1823 g_signal_connect(G_OBJECT(popup), "selection_done",
1824 G_CALLBACK(folderview_popup_close),
1826 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1827 event->button, event->time);
1830 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1831 FolderView *folderview)
1833 GtkCMCList *clist = GTK_CMCLIST(ctree);
1834 gint prev_row = -1, row = -1, column = -1;
1836 if (!event) return FALSE;
1838 if (event->button == 1 || event->button == 2) {
1839 if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist), event->x, event->y))
1840 folderview->open_folder = TRUE;
1842 if (event->type == GDK_2BUTTON_PRESS) {
1843 if (clist->selection) {
1844 GtkCMCTreeNode *node;
1846 node = GTK_CMCTREE_NODE(clist->selection->data);
1848 gtk_cmctree_toggle_expansion(
1851 folderview->open_folder = FALSE;
1858 if (event->button == 2 || event->button == 3) {
1860 if (clist->selection) {
1861 GtkCMCTreeNode *node;
1863 node = GTK_CMCTREE_NODE(clist->selection->data);
1865 prev_row = gtkut_ctree_get_nth_from_node
1866 (GTK_CMCTREE(ctree), node);
1869 if (!gtk_cmclist_get_selection_info(clist, event->x, event->y,
1872 if (prev_row != row) {
1873 gtk_cmclist_unselect_all(clist);
1874 if (event->button == 2)
1875 folderview_select_node
1877 gtk_cmctree_node_nth(GTK_CMCTREE(ctree),
1880 gtk_cmclist_select_row(clist, row, column);
1884 if (event->button != 3) return FALSE;
1886 folderview_set_sens_and_popup_menu(folderview, row, event);
1890 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1891 FolderView *folderview)
1893 int row = -1, column = -1;
1895 if (!event) return FALSE;
1897 if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree), event->x, event->y,
1900 if (event->button == 1 && folderview->open_folder == FALSE &&
1901 folderview->opened != NULL) {
1902 gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree),
1903 folderview->opened);
1904 gtk_cmctree_select(GTK_CMCTREE(ctree), folderview->opened);
1910 #define BREAK_ON_MODIFIER_KEY() \
1911 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
1913 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1914 FolderView *folderview)
1916 if (!event) return FALSE;
1918 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1921 switch (event->keyval) {
1923 #ifndef GENERIC_UMPC
1924 case GDK_KEY_Return:
1925 case GDK_KEY_KP_Enter:
1927 if (folderview->selected) {
1928 folderview_select_node(folderview,
1929 folderview->selected);
1933 case GDK_KEY_Return:
1934 if (folderview->selected && GTK_CMCTREE_ROW(folderview->selected)->children) {
1935 gtk_cmctree_toggle_expansion(
1936 GTK_CMCTREE(folderview->ctree),
1937 folderview->selected);
1942 BREAK_ON_MODIFIER_KEY();
1943 if (folderview->selected) {
1944 if (folderview->opened == folderview->selected &&
1945 (!folderview->summaryview->folder_item ||
1946 folderview->summaryview->folder_item->total_msgs == 0))
1947 folderview_select_next_with_flag(folderview, MSG_UNREAD, TRUE);
1949 folderview_select_node(folderview,
1950 folderview->selected);
1960 typedef struct _PostponedSelectData
1963 GtkCMCTreeNode *row;
1965 FolderView *folderview;
1966 } PostponedSelectData;
1968 static gboolean postpone_select(void *data)
1970 PostponedSelectData *psdata = (PostponedSelectData *)data;
1971 debug_print("trying again\n");
1973 psdata->folderview->postpone_select_id = 0;
1974 psdata->folderview->open_folder = TRUE;
1975 main_window_cursor_normal(psdata->folderview->mainwin);
1976 STATUSBAR_POP(psdata->folderview->mainwin);
1977 folderview_selected(psdata->ctree, psdata->row,
1978 psdata->column, psdata->folderview);
1983 void folderview_close_opened(FolderView *folderview)
1985 if (folderview->opened) {
1986 FolderItem *olditem;
1988 olditem = gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
1989 folderview->opened);
1991 gchar *buf = g_strdup_printf(_("Closing folder %s..."),
1992 olditem->path ? olditem->path:olditem->name);
1993 /* will be null if we just moved the previously opened folder */
1994 STATUSBAR_PUSH(folderview->mainwin, buf);
1995 main_window_cursor_wait(folderview->mainwin);
1997 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
1998 summary_show(folderview->summaryview, NULL);
1999 folder_item_close(olditem);
2000 main_window_cursor_normal(folderview->mainwin);
2001 STATUSBAR_POP(folderview->mainwin);
2002 if (olditem->folder->klass->item_closed)
2003 olditem->folder->klass->item_closed(olditem);
2008 if (folderview->opened &&
2009 !GTK_CMCTREE_ROW(folderview->opened)->children)
2010 gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree), folderview->opened);
2012 folderview->opened = NULL;
2014 static void folderview_selected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
2015 gint column, FolderView *folderview)
2017 static gboolean can_select = TRUE; /* exclusive lock */
2022 GtkCMCTreeNode *old_opened = folderview->opened;
2024 folderview->selected = row;
2026 debug_print("newly selected %p, opened %p\n", folderview->selected,
2027 folderview->opened);
2028 if (folderview->opened == row) {
2029 folderview->open_folder = FALSE;
2034 item = gtk_cmctree_node_get_row_data(ctree, row);
2037 folderview->open_folder = FALSE;
2041 if (!can_select || summary_is_locked(folderview->summaryview)) {
2042 if (folderview->opened) {
2043 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2044 gtk_cmctree_select(ctree, folderview->opened);
2046 folderview->open_folder = FALSE;
2051 if (!folderview->open_folder) {
2058 /* Save cache for old folder */
2059 /* We don't want to lose all caches if sylpheed crashed */
2060 /* resets folderview->opened to NULL */
2061 folderview_close_opened(folderview);
2063 /* CLAWS: set compose button type: news folder items
2064 * always have a news folder as parent */
2066 toolbar_set_compose_button
2067 (folderview->mainwin->toolbar,
2068 FOLDER_TYPE(item->folder) == F_NEWS ?
2069 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2072 debug_print("Folder %s is selected\n", item->path);
2074 if (!GTK_CMCTREE_ROW(row)->children)
2075 gtk_cmctree_expand(ctree, row);
2077 /* ungrab the mouse event */
2078 if (gtk_widget_has_grab(GTK_WIDGET(ctree))) {
2079 gtk_grab_remove(GTK_WIDGET(ctree));
2080 if (gdk_pointer_is_grabbed())
2081 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2085 /* TODO: wwp: avoid displaying (null) in the status bar */
2086 buf = g_strdup_printf(_("Opening folder %s..."), item->path ?
2087 item->path : "(null)");
2088 debug_print("%s\n", buf);
2089 STATUSBAR_PUSH(folderview->mainwin, buf);
2092 main_window_cursor_wait(folderview->mainwin);
2094 if (folderview->scanning_folder == item->folder) {
2097 res = folder_item_open(item);
2100 if (res == -1 && item->no_select == FALSE) {
2101 main_window_cursor_normal(folderview->mainwin);
2102 STATUSBAR_POP(folderview->mainwin);
2104 alertpanel_error(_("Folder could not be opened."));
2106 folderview->open_folder = FALSE;
2110 } else if (res == -2 && item->no_select == FALSE) {
2111 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2112 data->ctree = ctree;
2114 data->column = column;
2115 data->folderview = folderview;
2116 debug_print("postponing open of %s till end of scan\n",
2117 item->path ? item->path:item->name);
2118 folderview->open_folder = FALSE;
2120 if (folderview->postpone_select_id != 0)
2121 g_source_remove(folderview->postpone_select_id);
2122 folderview->postpone_select_id = g_timeout_add(500, postpone_select, data);
2127 main_window_cursor_normal(folderview->mainwin);
2130 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2131 opened = summary_show(folderview->summaryview, item);
2133 folder_clean_cache_memory(item);
2136 gtkut_ctree_set_focus_row(ctree, old_opened);
2137 gtk_cmctree_select(ctree, old_opened);
2138 folderview->opened = old_opened;
2140 folderview->opened = row;
2141 if (gtk_cmctree_node_is_visible(ctree, row)
2142 != GTK_VISIBILITY_FULL)
2143 gtk_cmctree_node_moveto(ctree, row, -1, 0.5, 0);
2146 STATUSBAR_POP(folderview->mainwin);
2148 folderview->open_folder = FALSE;
2153 static void folderview_tree_expanded(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2154 FolderView *folderview)
2158 item = gtk_cmctree_node_get_row_data(ctree, node);
2159 cm_return_if_fail(item != NULL);
2160 item->collapsed = FALSE;
2161 folderview_update_node(folderview, node);
2164 static void folderview_tree_collapsed(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2165 FolderView *folderview)
2169 item = gtk_cmctree_node_get_row_data(ctree, node);
2170 cm_return_if_fail(item != NULL);
2171 item->collapsed = TRUE;
2172 folderview_update_node(folderview, node);
2175 static void folderview_popup_close(GtkMenuShell *menu_shell,
2176 FolderView *folderview)
2178 if (!folderview->opened) return;
2180 gtk_cmctree_select(GTK_CMCTREE(folderview->ctree), folderview->opened);
2183 static void folderview_col_resized(GtkCMCList *clist, gint column, gint width,
2184 FolderView *folderview)
2186 FolderColumnType type = folderview->col_state[column].type;
2188 prefs_common.folder_col_size[type] = width;
2191 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2193 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2194 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2195 GtkCMCTreeNode *node, *parent_node;
2196 gint *col_pos = folderview->col_pos;
2197 FolderItemUpdateData hookdata;
2199 parent_node = gtk_cmctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2200 if (parent_node == NULL)
2203 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
2205 text[col_pos[F_COL_FOLDER]] = item->name;
2206 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2211 gtk_cmctree_expand(ctree, parent_node);
2212 gtk_cmctree_node_set_row_data(ctree, node, item);
2214 gtk_cmctree_node_set_row_style(ctree, node, normal_style);
2215 folderview_sort_folders(folderview, parent_node, item->folder);
2217 hookdata.item = item;
2218 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2219 hookdata.msg = NULL;
2220 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2222 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
2225 static void folderview_empty_trash_cb(GtkAction *action, gpointer data)
2227 FolderView *folderview = (FolderView *)data;
2228 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2230 GSList *mlist = NULL;
2232 FolderItem *special_trash = NULL;
2235 if (!folderview->selected) return;
2236 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2237 cm_return_if_fail(item != NULL);
2238 cm_return_if_fail(item->folder != NULL);
2240 if (NULL != (ac = account_find_from_item(item)))
2241 special_trash = account_get_special_folder(ac, F_TRASH);
2243 if (item != item->folder->trash && item != special_trash
2244 && !folder_has_parent_of_type(item, F_TRASH)) return;
2246 if (prefs_common.ask_on_clean) {
2247 if (alertpanel(_("Empty trash"),
2248 _("Delete all messages in trash?"),
2249 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2253 mlist = folder_item_get_msg_list(item);
2255 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2256 MsgInfo * msginfo = (MsgInfo *) cur->data;
2257 if (MSG_IS_LOCKED(msginfo->flags))
2259 /* is it partially received? (partial_recv isn't cached) */
2260 if (msginfo->total_size != 0 &&
2261 msginfo->size != (off_t)msginfo->total_size)
2262 partial_mark_for_delete(msginfo);
2264 procmsg_msg_list_free(mlist);
2266 folder_item_remove_all_msg(item);
2269 static void folderview_send_queue_cb(GtkAction *action, gpointer data)
2271 FolderView *folderview = (FolderView *)data;
2272 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2274 FolderItem *special_queue = NULL;
2276 gchar *errstr = NULL;
2278 if (!folderview->selected) return;
2279 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2280 cm_return_if_fail(item != NULL);
2281 cm_return_if_fail(item->folder != NULL);
2283 if (NULL != (ac = account_find_from_item(item)))
2284 special_queue = account_get_special_folder(ac, F_QUEUE);
2286 if (item != item->folder->queue && item != special_queue
2287 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2289 if (procmsg_queue_is_empty(item))
2292 if (prefs_common.work_offline)
2293 if (alertpanel(_("Offline warning"),
2294 _("You're working offline. Override?"),
2295 GTK_STOCK_NO, GTK_STOCK_YES,
2296 NULL) != G_ALERTALTERNATE)
2299 /* ask for confirmation before sending queued messages only
2300 in online mode and if there is at least one message queued
2301 in any of the folder queue
2303 if (prefs_common.confirm_send_queued_messages) {
2304 if (!prefs_common.work_offline) {
2305 if (alertpanel(_("Send queued messages"),
2306 _("Send all queued messages?"),
2307 GTK_STOCK_CANCEL, _("_Send"),
2308 NULL) != G_ALERTALTERNATE)
2313 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2315 alertpanel_error_log(_("Some errors occurred while "
2316 "sending queued messages."));
2318 alertpanel_error_log(_("Some errors occurred "
2319 "while sending queued messages:\n%s"), errstr);
2325 static void folderview_search_cb(GtkAction *action, gpointer data)
2327 FolderView *folderview = (FolderView *)data;
2328 summary_search(folderview->summaryview);
2331 static void folderview_run_processing_cb(GtkAction *action, gpointer data)
2333 FolderView *folderview = (FolderView *)data;
2334 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2337 if (!folderview->selected) return;
2339 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2340 cm_return_if_fail(item != NULL);
2341 cm_return_if_fail(item->folder != NULL);
2343 item->processing_pending = TRUE;
2344 folder_item_apply_processing(item);
2345 item->processing_pending = FALSE;
2348 static void folderview_property_cb(GtkAction *action, gpointer data)
2350 FolderView *folderview = (FolderView *)data;
2351 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2354 if (!folderview->selected) return;
2356 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2357 cm_return_if_fail(item != NULL);
2358 cm_return_if_fail(item->folder != NULL);
2360 prefs_folder_item_open(item);
2363 static void folderview_recollapse_nodes(FolderView *folderview, GtkCMCTreeNode *node)
2365 GSList *list = NULL;
2366 GSList *done = NULL;
2367 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2369 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2370 if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list->data), node)
2371 && list->data != node) {
2372 gtk_cmctree_collapse(ctree, GTK_CMCTREE_NODE(list->data));
2373 done = g_slist_append(done, GTK_CMCTREE_NODE(list->data));
2376 for (list = done; list != NULL; list = g_slist_next(list)) {
2377 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2383 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2384 FolderItem *to_folder, gboolean copy)
2386 FolderItem *new_folder = NULL;
2390 cm_return_if_fail(folderview != NULL);
2391 cm_return_if_fail(from_folder != NULL);
2392 cm_return_if_fail(to_folder != NULL);
2394 if (prefs_common.warn_dnd) {
2395 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s'?"):
2396 _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2397 from_folder->name, to_folder->name);
2398 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2399 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2400 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2403 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2405 else if (status & G_ALERTDISABLE)
2406 prefs_common.warn_dnd = FALSE;
2409 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2410 from_folder->name, to_folder->name);
2411 STATUSBAR_PUSH(folderview->mainwin, buf);
2413 summary_clear_all(folderview->summaryview);
2414 folderview->opened = NULL;
2415 folderview->selected = NULL;
2416 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2418 main_window_cursor_wait(folderview->mainwin);
2420 statusbar_verbosity_set(FALSE);
2421 folder_item_update_freeze();
2422 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2423 statusbar_verbosity_set(FALSE);
2424 main_window_cursor_normal(folderview->mainwin);
2425 STATUSBAR_POP(folderview->mainwin);
2426 folder_item_update_thaw();
2427 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2429 folderview_sort_folders(folderview,
2430 gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
2431 NULL, to_folder), new_folder->folder);
2432 folderview_select(folderview, new_folder);
2434 statusbar_verbosity_set(FALSE);
2435 main_window_cursor_normal(folderview->mainwin);
2436 STATUSBAR_POP(folderview->mainwin);
2437 folder_item_update_thaw();
2439 case F_MOVE_FAILED_DEST_IS_PARENT:
2440 alertpanel_error(_("Source and destination are the same."));
2442 case F_MOVE_FAILED_DEST_IS_CHILD:
2443 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2444 _("Can't move a folder to one of its children."));
2446 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2447 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2450 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2455 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2458 static gint folderview_clist_compare(GtkCMCList *clist,
2459 gconstpointer ptr1, gconstpointer ptr2)
2461 FolderItem *item1 = ((GtkCMCListRow *)ptr1)->data;
2462 FolderItem *item2 = ((GtkCMCListRow *)ptr2)->data;
2464 if (item1->order > 0 && item2->order > 0) // if we have an order item, use it
2466 return item1->order - item2->order;
2469 // if only one folder has an order it comes first
2470 if (item1->order > 0)
2474 if (item2->order > 0)
2480 return (item2->name != NULL);
2484 return g_utf8_collate(item1->name, item2->name);
2487 static void folderview_processing_cb(GtkAction *action, gpointer data)
2489 FolderView *folderview = (FolderView *)data;
2490 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2494 if (!folderview->selected) return;
2496 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2497 cm_return_if_fail(item != NULL);
2498 cm_return_if_fail(item->folder != NULL);
2500 id = folder_item_get_identifier(item);
2501 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2504 prefs_filtering_open(&item->prefs->processing, title,
2505 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2509 void folderview_set_target_folder_color(gint color_op)
2513 FolderView *folderview;
2515 for (list = folderview_list; list != NULL; list = list->next) {
2516 folderview = (FolderView *)list->data;
2517 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2519 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2520 folderview->color_op;
2526 static gchar *last_smallfont = NULL;
2527 static gchar *last_normalfont = NULL;
2528 static gchar *last_boldfont = NULL;
2529 static gboolean last_derive = 0;
2531 void folderview_reinit_fonts(FolderView *folderview)
2534 g_free(last_smallfont);
2535 last_smallfont = NULL;
2536 g_free(last_normalfont);
2537 last_normalfont = NULL;
2538 g_free(last_boldfont);
2539 last_boldfont = NULL;
2542 void folderview_reflect_prefs(void)
2544 gboolean update_font = FALSE;
2545 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2546 FolderItem *item = folderview_get_selected_item(folderview);
2547 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2548 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2549 gint height = gtk_adjustment_get_value(pos);
2551 if (!last_smallfont || strcmp(last_smallfont, SMALL_FONT) ||
2552 !last_normalfont || strcmp(last_normalfont, NORMAL_FONT) ||
2553 !last_boldfont || strcmp(last_boldfont, BOLD_FONT) ||
2554 last_derive != prefs_common.derive_from_normal_font)
2557 g_free(last_smallfont);
2558 last_smallfont = g_strdup(SMALL_FONT);
2559 g_free(last_normalfont);
2560 last_normalfont = g_strdup(NORMAL_FONT);
2561 g_free(last_boldfont);
2562 last_boldfont = g_strdup(BOLD_FONT);
2563 last_derive = prefs_common.derive_from_normal_font;
2566 normal_style = normal_color_style = bold_style =
2567 bold_color_style = bold_tgtfold_style = NULL;
2569 folderview_init(folderview);
2571 gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
2572 folderview_column_set_titles(folderview);
2573 folderview_set_all();
2575 g_signal_handlers_block_by_func
2576 (G_OBJECT(folderview->ctree),
2577 G_CALLBACK(folderview_selected), folderview);
2580 GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(
2581 GTK_CMCTREE(folderview->ctree), NULL, item);
2583 folderview_select(folderview, item);
2584 folderview->open_folder = FALSE;
2585 folderview->selected = node;
2588 g_signal_handlers_unblock_by_func
2589 (G_OBJECT(folderview->ctree),
2590 G_CALLBACK(folderview_selected), folderview);
2592 pos = gtk_scrolled_window_get_vadjustment(
2593 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2594 gtk_adjustment_set_value(pos, height);
2595 gtk_adjustment_changed(pos);
2596 gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2599 static void drag_state_stop(FolderView *folderview)
2601 if (folderview->drag_timer_id)
2602 g_source_remove(folderview->drag_timer_id);
2603 folderview->drag_timer_id = 0;
2604 folderview->drag_node = NULL;
2607 static gboolean folderview_defer_expand(FolderView *folderview)
2609 if (folderview->drag_node) {
2610 folderview_recollapse_nodes(folderview, folderview->drag_node);
2611 if (folderview->drag_item->collapsed) {
2612 gtk_cmctree_expand(GTK_CMCTREE(folderview->ctree), folderview->drag_node);
2613 folderview->nodes_to_recollapse = g_slist_append
2614 (folderview->nodes_to_recollapse, folderview->drag_node);
2617 folderview->drag_item = NULL;
2618 folderview->drag_timer_id = 0;
2622 static void drag_state_start(FolderView *folderview, GtkCMCTreeNode *node, FolderItem *item)
2624 /* the idea is that we call drag_state_start() whenever we want expansion to
2625 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2626 * we need to call drag_state_stop() */
2627 drag_state_stop(folderview);
2628 /* request expansion */
2629 if (0 != (folderview->drag_timer_id = g_timeout_add
2630 (prefs_common.hover_timeout,
2631 (GSourceFunc)folderview_defer_expand,
2633 folderview->drag_node = node;
2634 folderview->drag_item = item;
2637 #ifndef GENERIC_UMPC
2638 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2639 FolderView *folderview)
2641 GdkDragContext *context;
2643 cm_return_if_fail(folderview != NULL);
2644 if (folderview->selected == NULL) return;
2645 if (folderview->nodes_to_recollapse)
2646 g_slist_free(folderview->nodes_to_recollapse);
2647 folderview->nodes_to_recollapse = NULL;
2648 context = gtk_drag_begin(widget, folderview->target_list,
2649 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2650 gtk_drag_set_icon_default(context);
2653 static void folderview_drag_data_get(GtkWidget *widget,
2654 GdkDragContext *drag_context,
2655 GtkSelectionData *selection_data,
2658 FolderView *folderview)
2662 gchar *source = NULL;
2663 if (info == TARGET_DUMMY) {
2664 for (cur = GTK_CMCLIST(folderview->ctree)->selection;
2665 cur != NULL; cur = cur->next) {
2666 item = gtk_cmctree_node_get_row_data
2667 (GTK_CMCTREE(folderview->ctree),
2668 GTK_CMCTREE_NODE(cur->data));
2670 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2671 gtk_selection_data_set(selection_data,
2672 gtk_selection_data_get_target(selection_data), 8,
2673 source, strlen(source));
2679 g_warning("unknown info %d\n", info);
2683 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2685 FolderUpdateData *hookdata;
2686 FolderView *folderview;
2690 folderview = (FolderView *) userdata;
2691 cm_return_val_if_fail(hookdata != NULL, FALSE);
2692 cm_return_val_if_fail(folderview != NULL, FALSE);
2694 ctree = folderview->ctree;
2695 cm_return_val_if_fail(ctree != NULL, FALSE);
2697 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2698 folderview_create_folder_node(folderview, hookdata->item);
2699 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2700 GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree),
2701 NULL, folder_item_parent(hookdata->item));
2702 folderview_sort_folders(folderview, node, hookdata->folder);
2703 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2704 GtkCMCTreeNode *node;
2706 node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, hookdata->item);
2708 gtk_cmctree_remove_node(GTK_CMCTREE(ctree), node);
2709 if (folderview->selected == node)
2710 folderview->selected = NULL;
2711 if (folderview->opened == node)
2712 folderview->opened = NULL;
2714 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2715 folderview_set(folderview);
2720 static gboolean folderview_dnd_scroll_cb(gpointer data)
2722 FolderView *folderview = (FolderView *)data;
2723 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2724 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2725 gint new_val = (int)gtk_adjustment_get_value(pos) + folderview->scroll_value;
2726 gint max = (int)gtk_adjustment_get_upper(pos) -
2727 (int)gtk_adjustment_get_page_size(pos);
2729 if (folderview->scroll_value == 0) {
2730 folderview->scroll_timeout_id = 0;
2734 if (folderview->scroll_value > 0 && new_val > max) {
2736 } else if (folderview->scroll_value < 0 && new_val < 0) {
2739 gtk_adjustment_set_value(pos, new_val);
2744 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2745 GdkDragContext *context,
2749 FolderView *folderview)
2752 FolderItem *item = NULL, *src_item = NULL;
2753 GtkCMCTreeNode *node = NULL;
2754 gboolean acceptable = FALSE;
2755 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2756 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2757 int height = (int)gtk_adjustment_get_page_size(pos);
2758 int total_height = (int)gtk_adjustment_get_upper(pos);
2759 int vpos = (int)gtk_adjustment_get_value(pos);
2760 int offset = prefs_common.show_col_headers ? 24:0;
2763 if (gtk_cmclist_get_selection_info
2764 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column)) {
2765 GtkWidget *srcwidget;
2767 if (y > height - (48 - offset) && height + vpos < total_height) {
2768 dist = -(height - (48 - offset) - y);
2769 folderview->scroll_value = 1.41f * (1+(dist / 6));
2770 } else if (y < 72 - (24 - offset) && y >= 0) {
2771 dist = 72 - (24 - offset) - y;
2772 folderview->scroll_value = -1.41f * (1+(dist / 6));
2774 folderview->scroll_value = 0;
2776 if (folderview->scroll_value != 0 && folderview->scroll_timeout_id == 0) {
2777 folderview->scroll_timeout_id =
2778 g_timeout_add(30, folderview_dnd_scroll_cb,
2782 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
2783 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
2784 src_item = folderview->summaryview->folder_item;
2786 srcwidget = gtk_drag_get_source_widget(context);
2787 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2788 /* comes from summaryview */
2789 /* we are copying messages, so only accept folder items that are not
2790 the source item, are no root items and can copy messages */
2791 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2792 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2793 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2795 } else if (srcwidget == folderview->ctree) {
2796 /* comes from folderview */
2797 /* we are moving folder items, only accept folders that are not
2798 the source items and can copy messages and create folder items */
2799 if (item && item->folder && src_item && src_item != item &&
2800 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2801 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2802 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2803 || item->folder == src_item->folder))
2806 /* comes from another app */
2807 /* we are adding messages, so only accept folder items that are
2808 no root items and can copy messages */
2809 if (item && item->folder && folder_item_parent(item) != NULL
2810 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2811 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2816 if (acceptable || (src_item && src_item == item))
2817 drag_state_start(folderview, node, item);
2820 g_signal_handlers_block_by_func
2822 G_CALLBACK(folderview_selected), folderview);
2823 gtk_cmctree_select(GTK_CMCTREE(widget), node);
2824 g_signal_handlers_unblock_by_func
2826 G_CALLBACK(folderview_selected), folderview);
2827 gdk_drag_status(context,
2828 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
2829 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2831 if (folderview->opened)
2832 gtk_cmctree_select(GTK_CMCTREE(widget), folderview->opened);
2833 gdk_drag_status(context, 0, time);
2839 static void folderview_drag_leave_cb(GtkWidget *widget,
2840 GdkDragContext *context,
2842 FolderView *folderview)
2844 drag_state_stop(folderview);
2845 folderview->scroll_value = 0;
2846 gtk_cmctree_select(GTK_CMCTREE(widget), folderview->opened);
2849 static void free_info (gpointer stuff, gpointer data)
2854 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2855 guint time, FolderItem *item)
2858 GSList *msglist = NULL;
2859 list = uri_list_extract_filenames(data);
2860 if (!(item && item->folder && folder_item_parent(item) != NULL
2861 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2863 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2864 debug_print("item doesn't fit\n");
2868 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2869 debug_print("list is empty\n");
2872 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2873 MsgFileInfo *info = NULL;
2875 if (file_is_email((gchar *)tmp->data)) {
2876 info = g_new0(MsgFileInfo, 1);
2877 info->msginfo = NULL;
2878 info->file = (gchar *)tmp->data;
2879 msglist = g_slist_prepend(msglist, info);
2880 debug_print("file is a mail\n");
2882 debug_print("file isn't a mail\n");
2886 msglist = g_slist_reverse(msglist);
2887 folder_item_add_msgs(item, msglist, FALSE);
2888 g_slist_foreach(msglist, free_info, NULL);
2889 g_slist_free(msglist);
2890 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2892 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2894 list_free_strings(list);
2898 static void folderview_drag_received_cb(GtkWidget *widget,
2899 GdkDragContext *drag_context,
2902 GtkSelectionData *data,
2905 FolderView *folderview)
2908 FolderItem *item = NULL, *src_item;
2909 GtkCMCTreeNode *node;
2910 int offset = prefs_common.show_col_headers ? 24:0;
2912 folderview->scroll_value = 0;
2914 if (info == TARGET_DUMMY) {
2915 drag_state_stop(folderview);
2916 const gchar *ddata = (const gchar *)gtk_selection_data_get_data(data);
2917 if ((gchar *)strstr(ddata, "FROM_OTHER_FOLDER") != ddata) {
2918 /* comes from summaryview */
2919 if (gtk_cmclist_get_selection_info
2920 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0)
2923 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
2924 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
2925 src_item = folderview->summaryview->folder_item;
2927 if (item->no_select) {
2928 alertpanel_error(_("The destination folder can only be used to "
2929 "store subfolders."));
2932 /* re-check (due to acceptable possibly set for folder moves */
2933 if (!(item && item->folder && item->path && !item->no_select &&
2934 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2937 if (item && src_item) {
2938 switch (gdk_drag_context_get_selected_action(drag_context)) {
2939 case GDK_ACTION_COPY:
2940 summary_copy_selected_to(folderview->summaryview, item);
2941 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2943 case GDK_ACTION_MOVE:
2944 case GDK_ACTION_DEFAULT:
2946 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2947 summary_copy_selected_to(folderview->summaryview, item);
2949 summary_move_selected_to(folderview->summaryview, item);
2950 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2953 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2955 /* comes from folderview */
2957 gboolean folder_is_normal = TRUE;
2958 gboolean copy = (GDK_ACTION_COPY ==
2959 gdk_drag_context_get_selected_action(drag_context));
2961 source = (char *)gtk_selection_data_get_data(data) + 17;
2962 if (gtk_cmclist_get_selection_info
2963 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0
2965 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2968 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
2969 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
2970 src_item = folder_find_item_from_identifier(source);
2974 src_item->stype == F_NORMAL &&
2975 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2976 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2977 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2978 !folder_has_parent_of_type(src_item, F_TRASH);
2979 if (!item || !src_item || !folder_is_normal) {
2980 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2984 folderview_move_folder(folderview, src_item, item, copy);
2985 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2987 folderview->nodes_to_recollapse = NULL;
2988 } else if (info == TARGET_MAIL_URI_LIST) {
2989 if (gtk_cmclist_get_selection_info
2990 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0)
2993 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
2995 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2996 debug_print("no node\n");
2999 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3001 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3002 debug_print("no item\n");
3005 folderview_finish_dnd(gtk_selection_data_get_data(data),
3006 drag_context, time, item);
3010 static void folderview_drag_end_cb(GtkWidget *widget,
3011 GdkDragContext *drag_context,
3012 FolderView *folderview)
3014 drag_state_stop(folderview);
3015 folderview->scroll_value = 0;
3016 g_slist_free(folderview->nodes_to_recollapse);
3017 folderview->nodes_to_recollapse = NULL;
3020 void folderview_register_popup(FolderViewPopup *fpopup)
3024 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3025 FolderView *folderview = folderviews->data;
3026 GtkActionGroup *factory;
3028 factory = create_action_group(folderview, fpopup);
3029 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
3031 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
3034 void folderview_unregister_popup(FolderViewPopup *fpopup)
3039 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3040 FolderView *folderview = folderviews->data;
3042 g_hash_table_remove(folderview->popups, fpopup->klass);
3044 g_hash_table_remove(folderview_popups, fpopup->klass);