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;
687 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
688 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
689 if (prefs_common.derive_from_normal_font || !BOLD_FONT) {
690 pango_font_description_set_weight
691 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
693 PangoFontDescription *font_desc;
694 font_desc = pango_font_description_from_string(BOLD_FONT);
696 if (bold_style->font_desc)
697 pango_font_description_free
698 (bold_style->font_desc);
699 bold_style->font_desc = font_desc;
702 bold_color_style = gtk_style_copy(bold_style);
703 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
705 bold_tgtfold_style = gtk_style_copy(bold_style);
706 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
710 static gboolean folderview_defer_set(gpointer data)
712 FolderView *folderview = (FolderView *)data;
713 MainWindow *mainwin = folderview->mainwin;
717 if (mainwin->lock_count)
720 debug_print("doing deferred folderview_set now\n");
721 folderview_set(folderview);
723 folderview->deferred_refresh_id = 0;
727 void folderview_set(FolderView *folderview)
729 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
730 MainWindow *mainwin = folderview->mainwin;
731 FolderItem *sel_item = NULL, *op_item = NULL;
736 if (mainwin->lock_count) {
737 if (folderview->deferred_refresh_id == 0)
738 folderview->deferred_refresh_id =
739 g_timeout_add(500, folderview_defer_set, folderview);
740 debug_print("deferred folderview_set\n");
745 debug_print("Setting folder info...\n");
746 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
748 main_window_cursor_wait(mainwin);
750 if (folderview->selected)
751 sel_item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
752 if (folderview->opened)
753 op_item = gtk_cmctree_node_get_row_data(ctree, folderview->opened);
755 folderview->selected = NULL;
756 folderview->opened = NULL;
758 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
759 gtk_cmclist_clear(GTK_CMCLIST(ctree));
761 folderview_set_folders(folderview);
764 folderview->selected = gtk_cmctree_find_by_row_data(ctree, NULL, sel_item);
766 folderview->opened = gtk_cmctree_find_by_row_data(ctree, NULL, op_item);
768 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
769 main_window_cursor_normal(mainwin);
770 STATUSBAR_POP(mainwin);
774 void folderview_set_all(void)
778 for (list = folderview_list; list != NULL; list = list->next)
779 folderview_set((FolderView *)list->data);
782 void folderview_select(FolderView *folderview, FolderItem *item)
784 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
785 GtkCMCTreeNode *node;
786 GtkCMCTreeNode *old_selected = folderview->selected;
790 node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
791 if (node) folderview_select_node(folderview, node);
793 if (old_selected != node)
794 folder_update_op_count();
797 static void mark_all_read_cb(GtkAction *action, gpointer data)
799 FolderView *folderview = (FolderView *)data;
803 item = folderview_get_selected_item(folderview);
807 if (folderview->summaryview->folder_item != item
808 && prefs_common.ask_mark_all_read) {
809 val = alertpanel_full(_("Mark all as read"),
810 _("Do you really want to mark all mails in this "
811 "folder as read?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
812 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
814 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
816 else if (val & G_ALERTDISABLE)
817 prefs_common.ask_mark_all_read = FALSE;
821 folder_item_update_freeze();
822 if (folderview->summaryview->folder_item != item)
823 summary_lock(folderview->summaryview);
825 summary_freeze(folderview->summaryview);
827 folderutils_mark_all_read(item);
829 if (folderview->summaryview->folder_item != item)
830 summary_unlock(folderview->summaryview);
832 summary_thaw(folderview->summaryview);
833 folder_item_update_thaw();
836 static void folderview_select_node(FolderView *folderview, GtkCMCTreeNode *node)
838 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
840 cm_return_if_fail(node != NULL);
842 if (folderview->open_folder) {
846 folderview->open_folder = TRUE;
847 gtkut_ctree_set_focus_row(ctree, node);
848 gtk_cmctree_select(ctree, node);
849 if ((folderview->summaryview->folder_item &&
850 folderview->summaryview->folder_item->total_msgs > 0) ||
851 prefs_common.layout_mode == SMALL_LAYOUT)
852 summary_grab_focus(folderview->summaryview);
854 gtk_widget_grab_focus(folderview->ctree);
856 gtkut_ctree_expand_parent_all(ctree, node);
859 void folderview_unselect(FolderView *folderview)
861 if (folderview->opened && !GTK_CMCTREE_ROW(folderview->opened)->children)
863 (GTK_CMCTREE(folderview->ctree), folderview->opened);
865 folderview->selected = folderview->opened = NULL;
868 static GtkCMCTreeNode *folderview_find_next_with_flag(GtkCMCTree *ctree,
869 GtkCMCTreeNode *node,
875 node = gtkut_ctree_node_next(ctree, node);
877 node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
879 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
880 item = gtk_cmctree_node_get_row_data(ctree, node);
881 if (item->stype == F_TRASH || item->stype == F_DRAFT)
885 if(item->unread_msgs > 0)
889 if(item->new_msgs > 0)
893 if(item->marked_msgs > 0)
902 void folderview_select_next_with_flag(FolderView *folderview,
906 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
907 GtkCMCTreeNode *node = NULL;
908 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
909 gboolean last_open = prefs_common.always_show_msg;
913 prefs_common.summary_select_prio[0] = ACTION_UNREAD;
916 prefs_common.summary_select_prio[0] = ACTION_NEW;
919 prefs_common.summary_select_prio[0] = ACTION_MARKED;
922 prefs_common.always_show_msg = force_open ? OPENMSG_ALWAYS : last_open;
924 node = folderview_find_next_with_flag(ctree, folderview->opened, flag);
926 folderview_select_node(folderview, node);
930 if (!folderview->opened ||
931 folderview->opened == GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list)) {
935 /* search again from the first node */
936 node = folderview_find_next_with_flag(ctree, NULL, flag);
938 folderview_select_node(folderview, node);
941 prefs_common.summary_select_prio[0] = last_summary_select_prio;
942 prefs_common.always_show_msg = last_open;
945 FolderItem *folderview_get_selected_item(FolderView *folderview)
947 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
949 if (!folderview->selected) return NULL;
950 return gtk_cmctree_node_get_row_data(ctree, folderview->selected);
953 static void folderview_set_folders(FolderView *folderview)
956 list = folder_get_list();
958 for (; list != NULL; list = list->next) {
959 folderview_append_folder(folderview, FOLDER(list->data));
963 static gchar *get_scan_str(FolderItem *item)
966 return g_strdup_printf(_("Scanning folder %s%c%s..."),
967 item->folder->name, G_DIR_SEPARATOR,
970 return g_strdup_printf(_("Scanning folder %s..."),
973 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
977 for (list = folderview_list; list != NULL; list = list->next) {
978 FolderView *folderview = (FolderView *)list->data;
979 MainWindow *mainwin = folderview->mainwin;
980 gchar *str = get_scan_str(item);
982 STATUSBAR_PUSH(mainwin, str);
983 STATUSBAR_POP(mainwin);
988 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
991 MainWindow *mainwin = mainwindow_get_mainwindow();
992 FolderView *folderview = NULL;
993 GtkAdjustment *pos = NULL;
996 cm_return_if_fail(folder != NULL);
998 if (!folder->klass->scan_tree) return;
1001 alertpanel_full(_("Rebuild folder tree"),
1002 _("Rebuilding the folder tree will remove "
1003 "local caches. Do you want to continue?"),
1004 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1005 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1006 != G_ALERTALTERNATE) {
1012 window = label_window_create(_("Rebuilding folder tree..."));
1014 window = label_window_create(_("Scanning folder tree..."));
1017 folderview = mainwin->folderview;
1020 pos = gtk_scrolled_window_get_vadjustment(
1021 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1022 height = gtk_adjustment_get_value(pos);
1025 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1026 folder_scan_tree(folder, rebuild);
1027 folder_set_ui_func(folder, NULL, NULL);
1029 folderview_set_all();
1032 pos = gtk_scrolled_window_get_vadjustment(
1033 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1034 gtk_adjustment_set_value(pos, height);
1035 gtk_adjustment_changed(pos);
1037 label_window_destroy(window);
1041 /** folderview_check_new()
1042 * Scan and update the folder and return the
1043 * count the number of new messages since last check.
1044 * \param folder the folder to check for new messages
1045 * \return the number of new messages since last check
1047 gint folderview_check_new(Folder *folder)
1051 FolderView *folderview;
1053 GtkCMCTreeNode *node;
1055 gint former_new_msgs = 0;
1056 gint former_new = 0, former_unread = 0, former_total;
1058 for (list = folderview_list; list != NULL; list = list->next) {
1059 folderview = (FolderView *)list->data;
1060 ctree = GTK_CMCTREE(folderview->ctree);
1061 folderview->scanning_folder = folder;
1063 main_window_lock(folderview->mainwin);
1065 for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
1066 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1068 item = gtk_cmctree_node_get_row_data(ctree, node);
1069 if (!item || !item->path || !item->folder) continue;
1070 if (item->no_select) continue;
1071 if (folder && folder != item->folder) continue;
1072 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1073 if (!item->prefs->newmailcheck) continue;
1074 if (item->processing_pending == TRUE) {
1075 debug_print("skipping %s, processing pending\n",
1076 item->path ? item->path : item->name);
1079 if (item->scanning != ITEM_NOT_SCANNING) {
1080 debug_print("skipping %s, scanning\n",
1081 item->path ? item->path : item->name);
1085 str = get_scan_str(item);
1087 STATUSBAR_PUSH(folderview->mainwin, str);
1091 folderview_scan_tree_func(item->folder, item, NULL);
1092 former_new = item->new_msgs;
1093 former_unread = item->unread_msgs;
1094 former_total = item->total_msgs;
1096 if (item->folder->klass->scan_required &&
1097 (item->folder->klass->scan_required(item->folder, item) ||
1098 item->folder->inbox == item ||
1099 item->opened == TRUE ||
1100 item->processing_pending == TRUE)) {
1101 if (folder_item_scan(item) < 0) {
1103 summaryview_unlock(folderview->summaryview, item);
1104 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1105 log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
1106 item->path ? item->path:item->name);
1107 STATUSBAR_POP(folderview->mainwin);
1109 } else if (!FOLDER_IS_LOCAL(folder)) {
1110 STATUSBAR_POP(folderview->mainwin);
1115 } else if (!item->folder->klass->scan_required) {
1116 if (folder_item_scan(item) < 0) {
1117 summaryview_unlock(folderview->summaryview, item);
1118 if (folder && !FOLDER_IS_LOCAL(folder)) {
1119 STATUSBAR_POP(folderview->mainwin);
1124 if (former_new != item->new_msgs ||
1125 former_unread != item->unread_msgs ||
1126 former_total != item->total_msgs)
1127 folderview_update_node(folderview, node);
1129 new_msgs += item->new_msgs;
1130 former_new_msgs += former_new;
1131 STATUSBAR_POP(folderview->mainwin);
1133 folderview->scanning_folder = NULL;
1134 main_window_unlock(folderview->mainwin);
1138 folder_write_list();
1139 /* Number of new messages since last check is the just the difference
1140 * between former_new_msgs and new_msgs. If new_msgs is less than
1141 * former_new_msgs, that would mean another session accessed the folder
1142 * and the result is not well defined.
1144 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1148 void folderview_check_new_all(void)
1152 FolderView *folderview;
1154 folderview = (FolderView *)folderview_list->data;
1157 main_window_lock(folderview->mainwin);
1158 window = label_window_create
1159 (_("Checking for new messages in all folders..."));
1161 list = folder_get_list();
1162 for (; list != NULL; list = list->next) {
1163 Folder *folder = list->data;
1165 folderview_check_new(folder);
1168 folder_write_list();
1169 folderview_set_all();
1171 label_window_destroy(window);
1172 main_window_unlock(folderview->mainwin);
1176 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1182 if (!item || !item->folder || !item->folder->node)
1185 node = item->folder->node;
1187 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1188 node = node->children;
1191 (item->new_msgs > 0 ||
1192 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1196 while (node != NULL) {
1197 if (node && node->data) {
1198 FolderItem *next_item = (FolderItem*) node->data;
1200 if (folderview_have_new_children_sub(folderview,
1209 static gboolean folderview_have_new_children(FolderView *folderview,
1212 return folderview_have_new_children_sub(folderview, item, FALSE);
1215 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1221 if (!item || !item->folder || !item->folder->node)
1224 node = item->folder->node;
1226 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1227 node = node->children;
1230 (item->unread_msgs > 0 ||
1231 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1235 while (node != NULL) {
1236 if (node && node->data) {
1237 FolderItem *next_item = (FolderItem*) node->data;
1239 if (folderview_have_unread_children_sub(folderview,
1249 static gboolean folderview_have_unread_children(FolderView *folderview,
1252 return folderview_have_unread_children_sub(folderview, item, FALSE);
1255 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1261 if (!item || !item->folder || !item->folder->node)
1264 node = item->folder->node;
1266 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1267 node = node->children;
1269 if (in_sub && item->search_match){
1273 while (node != NULL) {
1274 if (node && node->data) {
1275 FolderItem *next_item = (FolderItem*) node->data;
1277 if (folderview_have_matching_children_sub(folderview,
1287 static gboolean folderview_have_matching_children(FolderView *folderview,
1290 return folderview_have_matching_children_sub(folderview, item, FALSE);
1293 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1299 if (!item || !item->folder || !item->folder->node)
1302 node = item->folder->node;
1304 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1305 node = node->children;
1307 if (item->marked_msgs != 0) {
1311 while (node != NULL) {
1312 if (node && node->data) {
1313 FolderItem *next_item = (FolderItem*) node->data;
1315 if (folderview_have_marked_children_sub(folderview,
1324 static gboolean folderview_have_marked_children(FolderView *folderview,
1327 return folderview_have_marked_children_sub(folderview, item, FALSE);
1330 static void folderview_update_node(FolderView *folderview, GtkCMCTreeNode *node)
1332 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1333 GtkStyle *style = NULL;
1334 GtkStyle *color_style = NULL;
1336 GdkPixbuf *xpm, *openxpm;
1337 static GdkPixbuf *searchicon;
1338 gboolean mark = FALSE;
1341 gboolean add_unread_mark;
1342 gboolean add_sub_match_mark;
1343 gboolean use_bold, use_color;
1344 gint *col_pos = folderview->col_pos;
1345 SpecialFolderItemType stype;
1347 item = gtk_cmctree_node_get_row_data(ctree, node);
1348 cm_return_if_fail(item != NULL);
1350 if (!GTK_CMCTREE_ROW(node)->expanded)
1351 mark = folderview_have_marked_children(folderview, item);
1353 mark = (item->marked_msgs != 0);
1355 stype = item->stype;
1356 if (stype == F_NORMAL) {
1357 if (folder_has_parent_of_type(item, F_TRASH))
1359 else if (folder_has_parent_of_type(item, F_DRAFT))
1361 else if (folder_has_parent_of_type(item, F_OUTBOX))
1363 else if (folder_has_parent_of_type(item, F_QUEUE))
1368 if (item->hide_read_msgs || item->hide_read_threads) {
1369 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1370 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1372 xpm = mark?m_inboxxpm:inboxxpm;
1373 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1377 if (item->hide_read_msgs || item->hide_read_threads) {
1378 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1379 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1381 xpm = mark?m_outboxxpm:outboxxpm;
1382 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1386 if (item->hide_read_msgs || item->hide_read_threads) {
1387 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1388 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1390 xpm = mark?m_queuexpm:queuexpm;
1391 openxpm = mark?m_queueopenxpm:queueopenxpm;
1395 if (item->hide_read_msgs || item->hide_read_threads) {
1396 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1397 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1399 xpm = mark?m_trashxpm:trashxpm;
1400 openxpm = mark?m_trashopenxpm:trashopenxpm;
1404 xpm = mark?m_draftsxpm:draftsxpm;
1405 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1408 if (item->hide_read_msgs || item->hide_read_threads) {
1409 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1410 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1412 xpm = mark?m_folderxpm:folderxpm;
1413 openxpm = mark?m_folderopenxpm:folderopenxpm;
1417 if (item->no_select) {
1418 xpm = openxpm = noselectxpm;
1421 name = folder_item_get_name(item);
1423 if (!GTK_CMCTREE_ROW(node)->expanded) {
1424 add_unread_mark = folderview_have_unread_children(
1426 add_sub_match_mark = folderview_have_matching_children(
1429 add_unread_mark = FALSE;
1430 add_sub_match_mark = FALSE;
1433 if (item->search_match) {
1435 stock_pixbuf_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1438 xpm = openxpm = searchicon;
1442 if (prefs_common.display_folder_unread) {
1443 if (folder_has_parent_of_type(item, F_QUEUE)) {
1444 /* only total_msgs matters here */
1445 if (item->total_msgs > 0) {
1446 /* show total number (should be equal to the unread number)
1448 str = g_strdup_printf("%s (%d%s%s)",
1449 name, item->total_msgs,
1450 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1451 (item->unreadmarked_msgs > 0) ? "!" : "");
1454 if (prefs_common.display_folder_unread == 1) {
1455 if (item->unread_msgs > 0) {
1456 /* show unread number and signs */
1457 str = g_strdup_printf("%s (%d%s%s)",
1458 name, item->unread_msgs,
1459 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1460 (item->unreadmarked_msgs > 0) ? "!" : "");
1463 if (item->total_msgs > 0) {
1464 /* show unread number, total number and signs if any */
1465 str = g_strdup_printf("%s (%d/%d%s%s)",
1466 name, item->unread_msgs, item->total_msgs,
1467 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1468 (item->unreadmarked_msgs > 0) ? "!" : "");
1472 if ((str == NULL) &&
1473 (add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
1474 /* no unread/total numbers, but at least one sign */
1475 str = g_strdup_printf("%s (%s%s)",
1477 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1478 (item->unreadmarked_msgs > 0) ? "!" : "");
1482 /* last fallback, folder name only or with +! sign */
1483 if (item->unreadmarked_msgs > 0 && add_sub_match_mark) {
1484 str = g_strdup_printf("%s%s",
1486 } else if (item->unreadmarked_msgs > 0) {
1487 str = g_strdup_printf("%s%s",
1489 } else if (add_sub_match_mark) {
1490 str = g_strdup_printf("%s%s",
1493 str = g_strdup_printf("%s", name);
1496 gtk_cmctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1498 FALSE, GTK_CMCTREE_ROW(node)->expanded);
1502 if (!folder_item_parent(item)) {
1503 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1504 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1505 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1507 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW], item->new_msgs > 0 ? itos(item->new_msgs) : prefs_common.zero_replacement);
1508 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
1509 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], item->total_msgs > 0 ? itos(item->total_msgs) : prefs_common.zero_replacement);
1512 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1513 folder_has_parent_of_type(item, F_TRASH)) {
1514 use_bold = use_color = FALSE;
1515 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1516 GSList *list = folder_item_get_msg_list(item);
1518 use_bold = use_color = FALSE;
1519 for (cur = list; cur; cur = cur->next) {
1520 MsgInfo *msginfo = (MsgInfo *)cur->data;
1521 if (!MSG_IS_DELETED(msginfo->flags)) {
1522 /* highlight queue folder if there are any messages */
1523 use_bold = use_color = TRUE;
1527 procmsg_msg_list_free(list);
1529 /* if unread messages exist, print with bold font */
1530 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1532 /* if new messages exist, print with colored letter */
1534 (item->new_msgs > 0) ||
1536 folderview_have_new_children(folderview, item));
1539 gtk_cmctree_node_set_foreground(ctree, node, NULL);
1544 if (item->prefs->color > 0 && !use_color) {
1545 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1546 color_style = gtk_style_copy(bold_style);
1547 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1548 style = color_style;
1549 } else if (use_color) {
1550 style = bold_color_style;
1553 if (item->op_count > 0) {
1554 style = bold_tgtfold_style;
1556 } else if (use_color) {
1557 style = normal_color_style;
1558 gtk_cmctree_node_set_foreground(ctree, node,
1559 &folderview->color_new);
1560 } else if (item->op_count > 0) {
1561 style = bold_tgtfold_style;
1562 } else if (item->prefs->color > 0) {
1564 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1565 color_style = gtk_style_copy(normal_style);
1566 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1567 style = color_style;
1569 style = normal_style;
1572 gtk_cmctree_node_set_row_style(ctree, node, style);
1574 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1575 folderview_update_node(folderview, node);
1578 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1581 FolderView *folderview;
1583 GtkCMCTreeNode *node;
1585 cm_return_if_fail(item != NULL);
1587 for (list = folderview_list; list != NULL; list = list->next) {
1588 folderview = (FolderView *)list->data;
1589 ctree = GTK_CMCTREE(folderview->ctree);
1591 node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
1592 if (node && item->search_match != matches) {
1593 item->search_match = matches;
1594 folderview_update_node(folderview, node);
1599 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1601 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1602 FolderView *folderview = (FolderView *)data;
1604 GtkCMCTreeNode *node;
1605 cm_return_val_if_fail(update_info != NULL, TRUE);
1606 cm_return_val_if_fail(update_info->item != NULL, TRUE);
1607 cm_return_val_if_fail(folderview != NULL, FALSE);
1609 ctree = GTK_CMCTREE(folderview->ctree);
1611 node = gtk_cmctree_find_by_row_data(ctree, NULL, update_info->item);
1614 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1615 folderview_update_node(folderview, node);
1617 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
1618 update_info->item == folderview->summaryview->folder_item &&
1619 update_info->item != NULL)
1620 if (!quicksearch_has_sat_predicate(folderview->summaryview->quicksearch))
1621 summary_show(folderview->summaryview, update_info->item);
1627 static gboolean folderview_gnode_func(GtkCMCTree *ctree, guint depth,
1628 GNode *gnode, GtkCMCTreeNode *cnode,
1631 FolderView *folderview = (FolderView *)data;
1632 FolderItem *item = FOLDER_ITEM(gnode->data);
1634 cm_return_val_if_fail(item != NULL, FALSE);
1636 gtk_cmctree_node_set_row_data(ctree, cnode, item);
1637 folderview_update_node(folderview, cnode);
1642 static void folderview_expand_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1645 FolderView *folderview = (FolderView *)data;
1648 if (GTK_CMCTREE_ROW(node)->children) {
1649 item = gtk_cmctree_node_get_row_data(ctree, node);
1650 cm_return_if_fail(item != NULL);
1652 if (!item->collapsed)
1653 gtk_cmctree_expand(ctree, node);
1655 folderview_update_node(folderview, node);
1659 static void set_special_folder(GtkCMCTree *ctree, FolderItem *item,
1660 GtkCMCTreeNode *root, GtkCMCTreeNode **prev)
1663 GtkCMCTreeNode *node, *parent, *sibling;
1665 node = gtk_cmctree_find_by_row_data(ctree, root, item);
1667 g_warning("%s not found.\n", item->path);
1669 parent = GTK_CMCTREE_ROW(node)->parent;
1670 if (*prev && parent == GTK_CMCTREE_ROW(*prev)->parent)
1671 sibling = GTK_CMCTREE_ROW(*prev)->sibling;
1673 sibling = GTK_CMCTREE_ROW(parent)->children;
1677 tmp = gtk_cmctree_node_get_row_data
1679 if (tmp->stype != F_NORMAL)
1680 sibling = GTK_CMCTREE_ROW(sibling)->sibling;
1684 if (node != sibling)
1685 gtk_cmctree_move(ctree, node, parent, sibling);
1692 static void folderview_sort_folders(FolderView *folderview, GtkCMCTreeNode *root,
1695 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1696 GtkCMCTreeNode *prev = NULL;
1698 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
1699 gtk_sctree_sort_recursive(ctree, root);
1700 if (root && GTK_CMCTREE_ROW(root)->parent) {
1701 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1704 set_special_folder(ctree, folder->inbox, root, &prev);
1705 set_special_folder(ctree, folder->outbox, root, &prev);
1706 set_special_folder(ctree, folder->draft, root, &prev);
1707 set_special_folder(ctree, folder->queue, root, &prev);
1708 set_special_folder(ctree, folder->trash, root, &prev);
1709 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1712 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1714 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1715 GtkCMCTreeNode *root;
1717 cm_return_if_fail(folder != NULL);
1719 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1720 folderview_gnode_func, folderview);
1721 gtk_cmctree_pre_recursive(ctree, root, folderview_expand_func,
1723 folderview_sort_folders(folderview, root, folder);
1726 /* callback functions */
1727 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1728 GdkEventButton *event)
1732 FolderViewPopup *fpopup;
1733 GtkActionGroup *action_group;
1735 FolderItem *special_trash = NULL, *special_queue = NULL;
1737 GtkUIManager *ui_manager = gtk_ui_manager_new();
1739 if (folderview->ui_manager)
1740 g_object_unref(folderview->ui_manager);
1742 folderview->ui_manager = ui_manager;
1743 item = folderview_get_selected_item(folderview);
1745 cm_return_if_fail(item != NULL);
1746 cm_return_if_fail(item->folder != NULL);
1747 folder = item->folder;
1749 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1752 action_group = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1754 fpopup = g_hash_table_lookup(folderview_popups, "common");
1755 action_group = g_hash_table_lookup(folderview->popups, "common");
1758 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1759 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR)
1760 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU)
1762 if (fpopup->add_menuitems)
1763 fpopup->add_menuitems(ui_manager, item);
1765 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM)
1766 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1767 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM)
1768 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM)
1769 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM)
1770 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM)
1772 if (fpopup->set_sensitivity != NULL)
1773 fpopup->set_sensitivity(ui_manager, item);
1775 if (NULL != (ac = account_find_from_item(item))) {
1776 special_trash = account_get_special_folder(ac, F_TRASH);
1777 special_queue = account_get_special_folder(ac, F_QUEUE);
1780 if ((item == folder->trash || item == special_trash
1781 || folder_has_parent_of_type(item, F_TRASH))) {
1782 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1783 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM)
1786 if ((item == folder->queue || item == special_queue
1787 || folder_has_parent_of_type(item, F_QUEUE))) {
1788 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1789 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM)
1792 #define SET_SENS(name, sens) \
1793 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1795 SET_SENS("FolderViewPopup/MarkAllRead", item->unread_msgs >= 1);
1796 SET_SENS("FolderViewPopup/SearchFolder", item->total_msgs >= 1 &&
1797 folderview->selected == folderview->opened);
1798 SET_SENS("FolderViewPopup/Properties", TRUE);
1800 SET_SENS("FolderViewPopup/RunProcessing", item->prefs->processing &&
1801 item->total_msgs >= 1 && !item->processing_pending);
1802 SET_SENS("FolderViewPopup/Processing", item->node->parent != NULL &&
1803 !item->no_select && !item->processing_pending);
1805 if (item == folder->trash || item == special_trash
1806 || folder_has_parent_of_type(item, F_TRASH)) {
1807 GSList *msglist = folder_item_get_msg_list(item);
1808 SET_SENS("FolderViewPopup/EmptyTrash", msglist != NULL);
1809 procmsg_msg_list_free(msglist);
1811 if (item == folder->queue || item == special_queue
1812 || folder_has_parent_of_type(item, F_QUEUE)) {
1813 GSList *msglist = folder_item_get_msg_list(item);
1814 SET_SENS("FolderViewPopup/SendQueue", msglist != NULL);
1815 procmsg_msg_list_free(msglist);
1819 popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1820 gtk_ui_manager_get_widget(ui_manager, "/Popup/FolderViewPopup")) );
1821 g_signal_connect(G_OBJECT(popup), "selection_done",
1822 G_CALLBACK(folderview_popup_close),
1824 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1825 event->button, event->time);
1828 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1829 FolderView *folderview)
1831 GtkCMCList *clist = GTK_CMCLIST(ctree);
1832 gint prev_row = -1, row = -1, column = -1;
1834 if (!event) return FALSE;
1836 if (event->button == 1 || event->button == 2) {
1837 if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist), event->x, event->y))
1838 folderview->open_folder = TRUE;
1840 if (event->type == GDK_2BUTTON_PRESS) {
1841 if (clist->selection) {
1842 GtkCMCTreeNode *node;
1844 node = GTK_CMCTREE_NODE(clist->selection->data);
1846 gtk_cmctree_toggle_expansion(
1849 folderview->open_folder = FALSE;
1856 if (event->button == 2 || event->button == 3) {
1858 if (clist->selection) {
1859 GtkCMCTreeNode *node;
1861 node = GTK_CMCTREE_NODE(clist->selection->data);
1863 prev_row = gtkut_ctree_get_nth_from_node
1864 (GTK_CMCTREE(ctree), node);
1867 if (!gtk_cmclist_get_selection_info(clist, event->x, event->y,
1870 if (prev_row != row) {
1871 gtk_cmclist_unselect_all(clist);
1872 if (event->button == 2)
1873 folderview_select_node
1875 gtk_cmctree_node_nth(GTK_CMCTREE(ctree),
1878 gtk_cmclist_select_row(clist, row, column);
1882 if (event->button != 3) return FALSE;
1884 folderview_set_sens_and_popup_menu(folderview, row, event);
1888 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1889 FolderView *folderview)
1891 int row = -1, column = -1;
1893 if (!event) return FALSE;
1895 if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree), event->x, event->y,
1898 if (event->button == 1 && folderview->open_folder == FALSE &&
1899 folderview->opened != NULL) {
1900 gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree),
1901 folderview->opened);
1902 gtk_cmctree_select(GTK_CMCTREE(ctree), folderview->opened);
1908 #define BREAK_ON_MODIFIER_KEY() \
1909 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
1911 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1912 FolderView *folderview)
1914 if (!event) return FALSE;
1916 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1919 switch (event->keyval) {
1921 #ifndef GENERIC_UMPC
1922 case GDK_KEY_Return:
1923 case GDK_KEY_KP_Enter:
1925 if (folderview->selected) {
1926 folderview_select_node(folderview,
1927 folderview->selected);
1931 case GDK_KEY_Return:
1932 if (folderview->selected && GTK_CMCTREE_ROW(folderview->selected)->children) {
1933 gtk_cmctree_toggle_expansion(
1934 GTK_CMCTREE(folderview->ctree),
1935 folderview->selected);
1940 BREAK_ON_MODIFIER_KEY();
1941 if (folderview->selected) {
1942 if (folderview->opened == folderview->selected &&
1943 (!folderview->summaryview->folder_item ||
1944 folderview->summaryview->folder_item->total_msgs == 0))
1945 folderview_select_next_with_flag(folderview, MSG_UNREAD, TRUE);
1947 folderview_select_node(folderview,
1948 folderview->selected);
1958 typedef struct _PostponedSelectData
1961 GtkCMCTreeNode *row;
1963 FolderView *folderview;
1964 } PostponedSelectData;
1966 static gboolean postpone_select(void *data)
1968 PostponedSelectData *psdata = (PostponedSelectData *)data;
1969 debug_print("trying again\n");
1971 psdata->folderview->postpone_select_id = 0;
1972 psdata->folderview->open_folder = TRUE;
1973 main_window_cursor_normal(psdata->folderview->mainwin);
1974 STATUSBAR_POP(psdata->folderview->mainwin);
1975 folderview_selected(psdata->ctree, psdata->row,
1976 psdata->column, psdata->folderview);
1981 void folderview_close_opened(FolderView *folderview)
1983 if (folderview->opened) {
1984 FolderItem *olditem;
1986 olditem = gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
1987 folderview->opened);
1989 gchar *buf = g_strdup_printf(_("Closing folder %s..."),
1990 olditem->path ? olditem->path:olditem->name);
1991 /* will be null if we just moved the previously opened folder */
1992 STATUSBAR_PUSH(folderview->mainwin, buf);
1993 main_window_cursor_wait(folderview->mainwin);
1995 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
1996 summary_show(folderview->summaryview, NULL);
1997 folder_item_close(olditem);
1998 main_window_cursor_normal(folderview->mainwin);
1999 STATUSBAR_POP(folderview->mainwin);
2000 if (olditem->folder->klass->item_closed)
2001 olditem->folder->klass->item_closed(olditem);
2006 if (folderview->opened &&
2007 !GTK_CMCTREE_ROW(folderview->opened)->children)
2008 gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree), folderview->opened);
2010 folderview->opened = NULL;
2012 static void folderview_selected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
2013 gint column, FolderView *folderview)
2015 static gboolean can_select = TRUE; /* exclusive lock */
2020 GtkCMCTreeNode *old_opened = folderview->opened;
2022 folderview->selected = row;
2024 debug_print("newly selected %p, opened %p\n", folderview->selected,
2025 folderview->opened);
2026 if (folderview->opened == row) {
2027 folderview->open_folder = FALSE;
2032 item = gtk_cmctree_node_get_row_data(ctree, row);
2035 folderview->open_folder = FALSE;
2039 if (!can_select || summary_is_locked(folderview->summaryview)) {
2040 if (folderview->opened) {
2041 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2042 gtk_cmctree_select(ctree, folderview->opened);
2044 folderview->open_folder = FALSE;
2049 if (!folderview->open_folder) {
2056 /* Save cache for old folder */
2057 /* We don't want to lose all caches if sylpheed crashed */
2058 /* resets folderview->opened to NULL */
2059 folderview_close_opened(folderview);
2061 /* CLAWS: set compose button type: news folder items
2062 * always have a news folder as parent */
2064 toolbar_set_compose_button
2065 (folderview->mainwin->toolbar,
2066 FOLDER_TYPE(item->folder) == F_NEWS ?
2067 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2070 debug_print("Folder %s is selected\n", item->path);
2072 if (!GTK_CMCTREE_ROW(row)->children)
2073 gtk_cmctree_expand(ctree, row);
2075 /* ungrab the mouse event */
2076 if (gtk_widget_has_grab(GTK_WIDGET(ctree))) {
2077 gtk_grab_remove(GTK_WIDGET(ctree));
2078 if (gdk_pointer_is_grabbed())
2079 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2083 /* TODO: wwp: avoid displaying (null) in the status bar */
2084 buf = g_strdup_printf(_("Opening folder %s..."), item->path ?
2085 item->path : "(null)");
2086 debug_print("%s\n", buf);
2087 STATUSBAR_PUSH(folderview->mainwin, buf);
2090 main_window_cursor_wait(folderview->mainwin);
2092 if (folderview->scanning_folder == item->folder) {
2095 res = folder_item_open(item);
2098 if (res == -1 && item->no_select == FALSE) {
2099 main_window_cursor_normal(folderview->mainwin);
2100 STATUSBAR_POP(folderview->mainwin);
2102 alertpanel_error(_("Folder could not be opened."));
2104 folderview->open_folder = FALSE;
2108 } else if (res == -2 && item->no_select == FALSE) {
2109 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2110 data->ctree = ctree;
2112 data->column = column;
2113 data->folderview = folderview;
2114 debug_print("postponing open of %s till end of scan\n",
2115 item->path ? item->path:item->name);
2116 folderview->open_folder = FALSE;
2118 if (folderview->postpone_select_id != 0)
2119 g_source_remove(folderview->postpone_select_id);
2120 folderview->postpone_select_id = g_timeout_add(500, postpone_select, data);
2125 main_window_cursor_normal(folderview->mainwin);
2128 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2129 opened = summary_show(folderview->summaryview, item);
2131 folder_clean_cache_memory(item);
2134 gtkut_ctree_set_focus_row(ctree, old_opened);
2135 gtk_cmctree_select(ctree, old_opened);
2136 folderview->opened = old_opened;
2138 folderview->opened = row;
2139 if (gtk_cmctree_node_is_visible(ctree, row)
2140 != GTK_VISIBILITY_FULL)
2141 gtk_cmctree_node_moveto(ctree, row, -1, 0.5, 0);
2144 STATUSBAR_POP(folderview->mainwin);
2146 folderview->open_folder = FALSE;
2151 static void folderview_tree_expanded(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2152 FolderView *folderview)
2156 item = gtk_cmctree_node_get_row_data(ctree, node);
2157 cm_return_if_fail(item != NULL);
2158 item->collapsed = FALSE;
2159 folderview_update_node(folderview, node);
2162 static void folderview_tree_collapsed(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2163 FolderView *folderview)
2167 item = gtk_cmctree_node_get_row_data(ctree, node);
2168 cm_return_if_fail(item != NULL);
2169 item->collapsed = TRUE;
2170 folderview_update_node(folderview, node);
2173 static void folderview_popup_close(GtkMenuShell *menu_shell,
2174 FolderView *folderview)
2176 if (!folderview->opened) return;
2178 gtk_cmctree_select(GTK_CMCTREE(folderview->ctree), folderview->opened);
2181 static void folderview_col_resized(GtkCMCList *clist, gint column, gint width,
2182 FolderView *folderview)
2184 FolderColumnType type = folderview->col_state[column].type;
2186 prefs_common.folder_col_size[type] = width;
2189 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2191 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2192 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2193 GtkCMCTreeNode *node, *parent_node;
2194 gint *col_pos = folderview->col_pos;
2195 FolderItemUpdateData hookdata;
2197 parent_node = gtk_cmctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2198 if (parent_node == NULL)
2201 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
2203 text[col_pos[F_COL_FOLDER]] = item->name;
2204 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2209 gtk_cmctree_expand(ctree, parent_node);
2210 gtk_cmctree_node_set_row_data(ctree, node, item);
2212 gtk_cmctree_node_set_row_style(ctree, node, normal_style);
2213 folderview_sort_folders(folderview, parent_node, item->folder);
2215 hookdata.item = item;
2216 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2217 hookdata.msg = NULL;
2218 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2220 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
2223 static void folderview_empty_trash_cb(GtkAction *action, gpointer data)
2225 FolderView *folderview = (FolderView *)data;
2226 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2228 GSList *mlist = NULL;
2230 FolderItem *special_trash = NULL;
2233 if (!folderview->selected) return;
2234 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2235 cm_return_if_fail(item != NULL);
2236 cm_return_if_fail(item->folder != NULL);
2238 if (NULL != (ac = account_find_from_item(item)))
2239 special_trash = account_get_special_folder(ac, F_TRASH);
2241 if (item != item->folder->trash && item != special_trash
2242 && !folder_has_parent_of_type(item, F_TRASH)) return;
2244 if (prefs_common.ask_on_clean) {
2245 if (alertpanel(_("Empty trash"),
2246 _("Delete all messages in trash?"),
2247 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2251 mlist = folder_item_get_msg_list(item);
2253 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2254 MsgInfo * msginfo = (MsgInfo *) cur->data;
2255 if (MSG_IS_LOCKED(msginfo->flags))
2257 /* is it partially received? (partial_recv isn't cached) */
2258 if (msginfo->total_size != 0 &&
2259 msginfo->size != (off_t)msginfo->total_size)
2260 partial_mark_for_delete(msginfo);
2262 procmsg_msg_list_free(mlist);
2264 folder_item_remove_all_msg(item);
2267 static void folderview_send_queue_cb(GtkAction *action, gpointer data)
2269 FolderView *folderview = (FolderView *)data;
2270 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2272 FolderItem *special_queue = NULL;
2274 gchar *errstr = NULL;
2276 if (!folderview->selected) return;
2277 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2278 cm_return_if_fail(item != NULL);
2279 cm_return_if_fail(item->folder != NULL);
2281 if (NULL != (ac = account_find_from_item(item)))
2282 special_queue = account_get_special_folder(ac, F_QUEUE);
2284 if (item != item->folder->queue && item != special_queue
2285 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2287 if (procmsg_queue_is_empty(item))
2290 if (prefs_common.work_offline)
2291 if (alertpanel(_("Offline warning"),
2292 _("You're working offline. Override?"),
2293 GTK_STOCK_NO, GTK_STOCK_YES,
2294 NULL) != G_ALERTALTERNATE)
2297 /* ask for confirmation before sending queued messages only
2298 in online mode and if there is at least one message queued
2299 in any of the folder queue
2301 if (prefs_common.confirm_send_queued_messages) {
2302 if (!prefs_common.work_offline) {
2303 if (alertpanel(_("Send queued messages"),
2304 _("Send all queued messages?"),
2305 GTK_STOCK_CANCEL, _("_Send"),
2306 NULL) != G_ALERTALTERNATE)
2311 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2313 alertpanel_error_log(_("Some errors occurred while "
2314 "sending queued messages."));
2316 alertpanel_error_log(_("Some errors occurred "
2317 "while sending queued messages:\n%s"), errstr);
2323 static void folderview_search_cb(GtkAction *action, gpointer data)
2325 FolderView *folderview = (FolderView *)data;
2326 summary_search(folderview->summaryview);
2329 static void folderview_run_processing_cb(GtkAction *action, gpointer data)
2331 FolderView *folderview = (FolderView *)data;
2332 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2335 if (!folderview->selected) return;
2337 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2338 cm_return_if_fail(item != NULL);
2339 cm_return_if_fail(item->folder != NULL);
2341 item->processing_pending = TRUE;
2342 folder_item_apply_processing(item);
2343 item->processing_pending = FALSE;
2346 static void folderview_property_cb(GtkAction *action, gpointer data)
2348 FolderView *folderview = (FolderView *)data;
2349 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2352 if (!folderview->selected) return;
2354 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2355 cm_return_if_fail(item != NULL);
2356 cm_return_if_fail(item->folder != NULL);
2358 prefs_folder_item_open(item);
2361 static void folderview_recollapse_nodes(FolderView *folderview, GtkCMCTreeNode *node)
2363 GSList *list = NULL;
2364 GSList *done = NULL;
2365 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2367 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2368 if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list->data), node)
2369 && list->data != node) {
2370 gtk_cmctree_collapse(ctree, GTK_CMCTREE_NODE(list->data));
2371 done = g_slist_append(done, GTK_CMCTREE_NODE(list->data));
2374 for (list = done; list != NULL; list = g_slist_next(list)) {
2375 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2381 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2382 FolderItem *to_folder, gboolean copy)
2384 FolderItem *new_folder = NULL;
2388 cm_return_if_fail(folderview != NULL);
2389 cm_return_if_fail(from_folder != NULL);
2390 cm_return_if_fail(to_folder != NULL);
2392 if (prefs_common.warn_dnd) {
2393 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s'?"):
2394 _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2395 from_folder->name, to_folder->name);
2396 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2397 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2398 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2401 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2403 else if (status & G_ALERTDISABLE)
2404 prefs_common.warn_dnd = FALSE;
2407 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2408 from_folder->name, to_folder->name);
2409 STATUSBAR_PUSH(folderview->mainwin, buf);
2411 summary_clear_all(folderview->summaryview);
2412 folderview->opened = NULL;
2413 folderview->selected = NULL;
2414 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2416 main_window_cursor_wait(folderview->mainwin);
2418 statusbar_verbosity_set(FALSE);
2419 folder_item_update_freeze();
2420 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2421 statusbar_verbosity_set(FALSE);
2422 main_window_cursor_normal(folderview->mainwin);
2423 STATUSBAR_POP(folderview->mainwin);
2424 folder_item_update_thaw();
2425 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2427 folderview_sort_folders(folderview,
2428 gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
2429 NULL, to_folder), new_folder->folder);
2430 folderview_select(folderview, new_folder);
2432 statusbar_verbosity_set(FALSE);
2433 main_window_cursor_normal(folderview->mainwin);
2434 STATUSBAR_POP(folderview->mainwin);
2435 folder_item_update_thaw();
2437 case F_MOVE_FAILED_DEST_IS_PARENT:
2438 alertpanel_error(_("Source and destination are the same."));
2440 case F_MOVE_FAILED_DEST_IS_CHILD:
2441 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2442 _("Can't move a folder to one of its children."));
2444 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2445 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2448 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2453 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2456 static gint folderview_clist_compare(GtkCMCList *clist,
2457 gconstpointer ptr1, gconstpointer ptr2)
2459 FolderItem *item1 = ((GtkCMCListRow *)ptr1)->data;
2460 FolderItem *item2 = ((GtkCMCListRow *)ptr2)->data;
2462 if (item1->order > 0 && item2->order > 0) // if we have an order item, use it
2464 return item1->order - item2->order;
2467 // if only one folder has an order it comes first
2468 if (item1->order > 0)
2472 if (item2->order > 0)
2478 return (item2->name != NULL);
2482 return g_utf8_collate(item1->name, item2->name);
2485 static void folderview_processing_cb(GtkAction *action, gpointer data)
2487 FolderView *folderview = (FolderView *)data;
2488 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2492 if (!folderview->selected) return;
2494 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2495 cm_return_if_fail(item != NULL);
2496 cm_return_if_fail(item->folder != NULL);
2498 id = folder_item_get_identifier(item);
2499 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2502 prefs_filtering_open(&item->prefs->processing, title,
2503 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2507 void folderview_set_target_folder_color(gint color_op)
2511 FolderView *folderview;
2513 for (list = folderview_list; list != NULL; list = list->next) {
2514 folderview = (FolderView *)list->data;
2515 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2517 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2518 folderview->color_op;
2524 static gchar *last_smallfont = NULL;
2525 static gchar *last_normalfont = NULL;
2526 static gchar *last_boldfont = NULL;
2527 static gboolean last_derive = 0;
2529 void folderview_reinit_fonts(FolderView *folderview)
2532 g_free(last_smallfont);
2533 last_smallfont = NULL;
2534 g_free(last_normalfont);
2535 last_normalfont = NULL;
2536 g_free(last_boldfont);
2537 last_boldfont = NULL;
2540 void folderview_reflect_prefs(void)
2542 gboolean update_font = FALSE;
2543 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2544 FolderItem *item = folderview_get_selected_item(folderview);
2545 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2546 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2547 gint height = gtk_adjustment_get_value(pos);
2549 if (!last_smallfont || strcmp(last_smallfont, SMALL_FONT) ||
2550 !last_normalfont || strcmp(last_normalfont, NORMAL_FONT) ||
2551 !last_boldfont || strcmp(last_boldfont, BOLD_FONT) ||
2552 last_derive != prefs_common.derive_from_normal_font)
2555 g_free(last_smallfont);
2556 last_smallfont = g_strdup(SMALL_FONT);
2557 g_free(last_normalfont);
2558 last_normalfont = g_strdup(NORMAL_FONT);
2559 g_free(last_boldfont);
2560 last_boldfont = g_strdup(BOLD_FONT);
2561 last_derive = prefs_common.derive_from_normal_font;
2564 normal_style = normal_color_style = bold_style =
2565 bold_color_style = bold_tgtfold_style = NULL;
2567 folderview_init(folderview);
2569 gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
2570 folderview_column_set_titles(folderview);
2571 folderview_set_all();
2573 g_signal_handlers_block_by_func
2574 (G_OBJECT(folderview->ctree),
2575 G_CALLBACK(folderview_selected), folderview);
2578 GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(
2579 GTK_CMCTREE(folderview->ctree), NULL, item);
2581 folderview_select(folderview, item);
2582 folderview->open_folder = FALSE;
2583 folderview->selected = node;
2586 g_signal_handlers_unblock_by_func
2587 (G_OBJECT(folderview->ctree),
2588 G_CALLBACK(folderview_selected), folderview);
2590 pos = gtk_scrolled_window_get_vadjustment(
2591 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2592 gtk_adjustment_set_value(pos, height);
2593 gtk_adjustment_changed(pos);
2594 gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2597 static void drag_state_stop(FolderView *folderview)
2599 if (folderview->drag_timer_id)
2600 g_source_remove(folderview->drag_timer_id);
2601 folderview->drag_timer_id = 0;
2602 folderview->drag_node = NULL;
2605 static gboolean folderview_defer_expand(FolderView *folderview)
2607 if (folderview->drag_node) {
2608 folderview_recollapse_nodes(folderview, folderview->drag_node);
2609 if (folderview->drag_item->collapsed) {
2610 gtk_cmctree_expand(GTK_CMCTREE(folderview->ctree), folderview->drag_node);
2611 folderview->nodes_to_recollapse = g_slist_append
2612 (folderview->nodes_to_recollapse, folderview->drag_node);
2615 folderview->drag_item = NULL;
2616 folderview->drag_timer_id = 0;
2620 static void drag_state_start(FolderView *folderview, GtkCMCTreeNode *node, FolderItem *item)
2622 /* the idea is that we call drag_state_start() whenever we want expansion to
2623 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2624 * we need to call drag_state_stop() */
2625 drag_state_stop(folderview);
2626 /* request expansion */
2627 if (0 != (folderview->drag_timer_id = g_timeout_add
2628 (prefs_common.hover_timeout,
2629 (GSourceFunc)folderview_defer_expand,
2631 folderview->drag_node = node;
2632 folderview->drag_item = item;
2635 #ifndef GENERIC_UMPC
2636 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2637 FolderView *folderview)
2639 GdkDragContext *context;
2641 cm_return_if_fail(folderview != NULL);
2642 if (folderview->selected == NULL) return;
2643 if (folderview->nodes_to_recollapse)
2644 g_slist_free(folderview->nodes_to_recollapse);
2645 folderview->nodes_to_recollapse = NULL;
2646 context = gtk_drag_begin(widget, folderview->target_list,
2647 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2648 gtk_drag_set_icon_default(context);
2651 static void folderview_drag_data_get(GtkWidget *widget,
2652 GdkDragContext *drag_context,
2653 GtkSelectionData *selection_data,
2656 FolderView *folderview)
2660 gchar *source = NULL;
2661 if (info == TARGET_DUMMY) {
2662 for (cur = GTK_CMCLIST(folderview->ctree)->selection;
2663 cur != NULL; cur = cur->next) {
2664 item = gtk_cmctree_node_get_row_data
2665 (GTK_CMCTREE(folderview->ctree),
2666 GTK_CMCTREE_NODE(cur->data));
2668 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2669 gtk_selection_data_set(selection_data,
2670 gtk_selection_data_get_target(selection_data), 8,
2671 source, strlen(source));
2677 g_warning("unknown info %d\n", info);
2681 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2683 FolderUpdateData *hookdata;
2684 FolderView *folderview;
2688 folderview = (FolderView *) userdata;
2689 cm_return_val_if_fail(hookdata != NULL, FALSE);
2690 cm_return_val_if_fail(folderview != NULL, FALSE);
2692 ctree = folderview->ctree;
2693 cm_return_val_if_fail(ctree != NULL, FALSE);
2695 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2696 folderview_create_folder_node(folderview, hookdata->item);
2697 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2698 GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree),
2699 NULL, folder_item_parent(hookdata->item));
2700 folderview_sort_folders(folderview, node, hookdata->folder);
2701 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2702 GtkCMCTreeNode *node;
2704 node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, hookdata->item);
2706 gtk_cmctree_remove_node(GTK_CMCTREE(ctree), node);
2707 if (folderview->selected == node)
2708 folderview->selected = NULL;
2709 if (folderview->opened == node)
2710 folderview->opened = NULL;
2712 } else if (hookdata->update_flags & FOLDER_MOVE_FOLDERITEM) {
2713 /* do nothing, it's done by the ADD and REMOVE) */
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);