2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkitemfactory.h>
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
68 #include "quicksearch.h"
72 #define COL_FOLDER_WIDTH 150
73 #define COL_NUM_WIDTH 32
75 static GList *folderview_list = NULL;
77 static GtkStyle *normal_style;
78 static GtkStyle *normal_color_style;
79 static GtkStyle *bold_style;
80 static GtkStyle *bold_color_style;
81 static GtkStyle *bold_tgtfold_style;
83 static GdkPixmap *inboxxpm;
84 static GdkBitmap *inboxxpmmask;
85 static GdkPixmap *inboxhrmxpm;
86 static GdkBitmap *inboxhrmxpmmask;
87 static GdkPixmap *inboxopenxpm;
88 static GdkBitmap *inboxopenxpmmask;
89 static GdkPixmap *inboxopenhrmxpm;
90 static GdkBitmap *inboxopenhrmxpmmask;
91 static GdkPixmap *outboxxpm;
92 static GdkBitmap *outboxxpmmask;
93 static GdkPixmap *outboxhrmxpm;
94 static GdkBitmap *outboxhrmxpmmask;
95 static GdkPixmap *outboxopenxpm;
96 static GdkBitmap *outboxopenxpmmask;
97 static GdkPixmap *outboxopenhrmxpm;
98 static GdkBitmap *outboxopenhrmxpmmask;
99 static GdkPixmap *folderxpm;
100 static GdkBitmap *folderxpmmask;
101 static GdkPixmap *folderhrmxpm;
102 static GdkBitmap *folderhrmxpmmask;
103 static GdkPixmap *folderopenxpm;
104 static GdkBitmap *folderopenxpmmask;
105 static GdkPixmap *folderopenhrmxpm;
106 static GdkBitmap *folderopenhrmxpmmask;
107 static GdkPixmap *trashopenxpm;
108 static GdkBitmap *trashopenxpmmask;
109 static GdkPixmap *trashopenhrmxpm;
110 static GdkBitmap *trashopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
115 static GdkPixmap *queuexpm;
116 static GdkBitmap *queuexpmmask;
117 static GdkPixmap *queuehrmxpm;
118 static GdkBitmap *queuehrmxpmmask;
119 static GdkPixmap *queueopenxpm;
120 static GdkBitmap *queueopenxpmmask;
121 static GdkPixmap *queueopenhrmxpm;
122 static GdkBitmap *queueopenhrmxpmmask;
123 static GdkPixmap *draftsxpm;
124 static GdkBitmap *draftsxpmmask;
125 static GdkPixmap *draftsopenxpm;
126 static GdkBitmap *draftsopenxpmmask;
127 static GdkPixmap *noselectxpm;
128 static GdkBitmap *noselectxpmmask;
130 static GdkPixmap *m_inboxxpm;
131 static GdkBitmap *m_inboxxpmmask;
132 static GdkPixmap *m_inboxhrmxpm;
133 static GdkBitmap *m_inboxhrmxpmmask;
134 static GdkPixmap *m_inboxopenxpm;
135 static GdkBitmap *m_inboxopenxpmmask;
136 static GdkPixmap *m_inboxopenhrmxpm;
137 static GdkBitmap *m_inboxopenhrmxpmmask;
138 static GdkPixmap *m_outboxxpm;
139 static GdkBitmap *m_outboxxpmmask;
140 static GdkPixmap *m_outboxhrmxpm;
141 static GdkBitmap *m_outboxhrmxpmmask;
142 static GdkPixmap *m_outboxopenxpm;
143 static GdkBitmap *m_outboxopenxpmmask;
144 static GdkPixmap *m_outboxopenhrmxpm;
145 static GdkBitmap *m_outboxopenhrmxpmmask;
146 static GdkPixmap *m_folderxpm;
147 static GdkBitmap *m_folderxpmmask;
148 static GdkPixmap *m_folderhrmxpm;
149 static GdkBitmap *m_folderhrmxpmmask;
150 static GdkPixmap *m_folderopenxpm;
151 static GdkBitmap *m_folderopenxpmmask;
152 static GdkPixmap *m_folderopenhrmxpm;
153 static GdkBitmap *m_folderopenhrmxpmmask;
154 static GdkPixmap *m_trashopenxpm;
155 static GdkBitmap *m_trashopenxpmmask;
156 static GdkPixmap *m_trashopenhrmxpm;
157 static GdkBitmap *m_trashopenhrmxpmmask;
158 static GdkPixmap *m_trashxpm;
159 static GdkBitmap *m_trashxpmmask;
160 static GdkPixmap *m_trashhrmxpm;
161 static GdkBitmap *m_trashhrmxpmmask;
162 static GdkPixmap *m_queuexpm;
163 static GdkBitmap *m_queuexpmmask;
164 static GdkPixmap *m_queuehrmxpm;
165 static GdkBitmap *m_queuehrmxpmmask;
166 static GdkPixmap *m_queueopenxpm;
167 static GdkBitmap *m_queueopenxpmmask;
168 static GdkPixmap *m_queueopenhrmxpm;
169 static GdkBitmap *m_queueopenhrmxpmmask;
170 static GdkPixmap *m_draftsxpm;
171 static GdkBitmap *m_draftsxpmmask;
172 static GdkPixmap *m_draftsopenxpm;
173 static GdkBitmap *m_draftsopenxpmmask;
175 static GdkPixmap *newxpm;
176 static GdkBitmap *newxpmmask;
177 static GdkPixmap *unreadxpm;
178 static GdkBitmap *unreadxpmmask;
179 static GdkPixmap *readxpm;
180 static GdkBitmap *readxpmmask;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 void folderview_create_folder_node (FolderView *folderview,
277 gboolean folderview_update_folder (gpointer source,
279 gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {"/---", NULL, NULL, 0, "<Separator>"},
292 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
293 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
294 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
297 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
298 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
299 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
302 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
303 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
304 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
308 GtkTargetEntry folderview_drag_types[] =
310 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
311 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
314 void folderview_initialize(void)
316 FolderViewPopup *fpopup;
318 GSList *entries = NULL;
320 fpopup = g_new0(FolderViewPopup, 1);
322 n_entries = sizeof(folderview_common_popup_entries) /
323 sizeof(folderview_common_popup_entries[0]);
324 for (i = 0; i < n_entries; i++)
325 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
327 fpopup->klass = "common";
328 fpopup->path = "<CommonFolder>";
329 fpopup->entries = entries;
330 fpopup->set_sensitivity = NULL;
332 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
333 g_hash_table_insert(folderview_popups, "common", fpopup);
336 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
339 GtkItemFactory *factory;
340 FolderViewPopup *fpopup_common;
343 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
344 gtk_item_factory_set_translate_func(factory, menu_translate,
347 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
348 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
350 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
351 if (fpopup_common != fpopup)
352 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
353 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
355 popup = gtk_item_factory_get_widget(factory, fpopup->path);
356 g_signal_connect(G_OBJECT(popup), "selection_done",
357 G_CALLBACK(folderview_popup_close),
363 static void create_ifactories(gpointer key, gpointer value, gpointer data)
365 FolderView *folderview = data;
366 FolderViewPopup *fpopup = value;
367 GtkItemFactory *factory;
369 factory = create_ifactory(folderview, fpopup);
370 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
373 static void folderview_column_set_titles(FolderView *folderview)
375 GtkWidget *ctree = folderview->ctree;
376 GtkWidget *label_new;
377 GtkWidget *label_unread;
378 GtkWidget *label_total;
380 GtkWidget *hbox_unread;
381 GtkWidget *hbox_total;
382 gint *col_pos = folderview->col_pos;
384 debug_print("setting titles...\n");
385 gtk_widget_realize(folderview->ctree);
386 gtk_widget_show_all(folderview->scrolledwin);
388 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
389 * instead text (text overflows making them unreadable and ugly) */
390 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
391 &newxpm, &newxpmmask);
392 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
393 &unreadxpm, &unreadxpmmask);
394 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
395 &readxpm, &readxpmmask);
397 label_new = gtk_pixmap_new(newxpm, newxpmmask);
398 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
399 label_total = gtk_pixmap_new(readxpm, readxpmmask);
401 gtk_clist_column_titles_active(GTK_CLIST(ctree));
403 hbox_new = gtk_hbox_new(FALSE, 4);
404 hbox_unread = gtk_hbox_new(FALSE, 4);
405 hbox_total = gtk_hbox_new(FALSE, 4);
408 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
409 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
410 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
411 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
412 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
413 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
415 gtk_widget_show_all(hbox_new);
416 gtk_widget_show_all(hbox_unread);
417 gtk_widget_show_all(hbox_total);
419 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
420 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
421 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
423 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
424 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
425 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
428 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
430 FolderView *folderview = (FolderView *)data;
431 GdkEventButton event;
432 if (folderview_get_selected_item(folderview) == NULL)
436 event.time = gtk_get_current_event_time();
438 folderview_set_sens_and_popup_menu(folderview, -1,
445 GtkWidget *folderview_ctree_create(FolderView *folderview)
449 FolderColumnState *col_state;
450 FolderColumnType type;
451 gchar *titles[N_FOLDER_COLS];
453 GtkWidget *scrolledwin = folderview->scrolledwin;
455 debug_print("creating tree...\n");
456 memset(titles, 0, sizeof(titles));
458 col_state = prefs_folder_column_get_config();
459 memset(titles, 0, sizeof(titles));
461 col_pos = folderview->col_pos;
463 for (i = 0; i < N_FOLDER_COLS; i++) {
464 folderview->col_state[i] = col_state[i];
465 type = col_state[i].type;
469 titles[col_pos[F_COL_FOLDER]] = _("Folder");
470 titles[col_pos[F_COL_NEW]] = _("New");
471 titles[col_pos[F_COL_UNREAD]] = _("Unread");
472 /* TRANSLATORS: This in Number sign in American style */
473 titles[col_pos[F_COL_TOTAL]] = _("#");
475 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
478 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
479 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
481 gtk_clist_set_column_justification(GTK_CLIST(ctree),
482 col_pos[F_COL_UNREAD],
484 gtk_clist_set_column_justification(GTK_CLIST(ctree),
485 col_pos[F_COL_TOTAL],
487 if (prefs_common.enable_dotted_lines) {
488 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
489 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
490 GTK_CTREE_EXPANDER_SQUARE);
492 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
493 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
494 GTK_CTREE_EXPANDER_TRIANGLE);
497 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
498 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
500 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
501 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
503 /* don't let title buttons take key focus */
504 for (i = 0; i < N_FOLDER_COLS; i++) {
505 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
507 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
508 prefs_common.folder_col_size[i]);
509 gtk_clist_set_column_visibility
510 (GTK_CLIST(ctree), i, col_state[i].visible);
513 g_signal_connect(G_OBJECT(ctree), "key_press_event",
514 G_CALLBACK(folderview_key_pressed),
516 g_signal_connect(G_OBJECT(ctree), "button_press_event",
517 G_CALLBACK(folderview_button_pressed),
519 g_signal_connect(G_OBJECT(ctree), "popup-menu",
520 G_CALLBACK(folderview_popup_menu), folderview);
521 g_signal_connect(G_OBJECT(ctree), "button_release_event",
522 G_CALLBACK(folderview_button_released),
524 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
525 G_CALLBACK(folderview_selected), folderview);
526 g_signal_connect(G_OBJECT(ctree), "start_drag",
527 G_CALLBACK(folderview_start_drag), folderview);
528 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
529 G_CALLBACK(folderview_drag_data_get),
532 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
533 G_CALLBACK(folderview_tree_expanded),
535 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
536 G_CALLBACK(folderview_tree_collapsed),
539 g_signal_connect(G_OBJECT(ctree), "resize_column",
540 G_CALLBACK(folderview_col_resized),
544 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
545 folderview_drag_types, 2,
546 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
547 g_signal_connect(G_OBJECT(ctree), "drag_motion",
548 G_CALLBACK(folderview_drag_motion_cb),
550 g_signal_connect(G_OBJECT(ctree), "drag_leave",
551 G_CALLBACK(folderview_drag_leave_cb),
553 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
554 G_CALLBACK(folderview_drag_received_cb),
556 g_signal_connect(G_OBJECT(ctree), "drag_end",
557 G_CALLBACK(folderview_drag_end_cb),
560 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
565 void folderview_set_column_order(FolderView *folderview)
568 FolderItem *item = folderview_get_selected_item(folderview);
569 GtkWidget *scrolledwin = folderview->scrolledwin;
571 debug_print("recreating tree...\n");
572 gtk_widget_destroy(folderview->ctree);
574 folderview->ctree = ctree = folderview_ctree_create(folderview);
575 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
576 GTK_CLIST(ctree)->hadjustment);
577 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
578 GTK_CLIST(ctree)->vadjustment);
579 gtk_widget_show(ctree);
581 folderview_set(folderview);
582 folderview_column_set_titles(folderview);
584 folderview_select(folderview,item);
587 FolderView *folderview_create(void)
589 FolderView *folderview;
590 GtkWidget *scrolledwin;
593 debug_print("Creating folder view...\n");
594 folderview = g_new0(FolderView, 1);
596 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
597 gtk_scrolled_window_set_policy
598 (GTK_SCROLLED_WINDOW(scrolledwin),
599 GTK_POLICY_AUTOMATIC,
600 prefs_common.folderview_vscrollbar_policy);
601 gtk_widget_set_size_request(scrolledwin,
602 prefs_common.folderview_width,
603 prefs_common.folderview_height);
605 folderview->scrolledwin = scrolledwin;
606 ctree = folderview_ctree_create(folderview);
608 /* create popup factories */
609 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
610 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
612 folderview->ctree = ctree;
614 folderview->folder_update_callback_id =
615 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
616 folderview->folder_item_update_callback_id =
617 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
619 gtk_widget_show_all(scrolledwin);
621 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
622 folderview_list = g_list_append(folderview_list, folderview);
627 void folderview_init(FolderView *folderview)
629 GtkWidget *ctree = folderview->ctree;
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
671 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
677 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
680 PangoFontDescription *font_desc;
681 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
682 font_desc = pango_font_description_from_string(NORMAL_FONT);
684 if (normal_style->font_desc)
685 pango_font_description_free
686 (normal_style->font_desc);
687 normal_style->font_desc = font_desc;
689 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
690 normal_color_style = gtk_style_copy(normal_style);
691 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
693 gtk_widget_set_style(ctree, normal_style);
697 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
698 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
699 pango_font_description_set_weight
700 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
701 bold_color_style = gtk_style_copy(bold_style);
702 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
704 bold_tgtfold_style = gtk_style_copy(bold_style);
705 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
709 void folderview_set(FolderView *folderview)
711 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
712 MainWindow *mainwin = folderview->mainwin;
717 debug_print("Setting folder info...\n");
718 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
720 main_window_cursor_wait(mainwin);
722 folderview->selected = NULL;
723 folderview->opened = NULL;
725 gtk_clist_freeze(GTK_CLIST(ctree));
726 gtk_clist_clear(GTK_CLIST(ctree));
727 gtk_clist_thaw(GTK_CLIST(ctree));
728 gtk_clist_freeze(GTK_CLIST(ctree));
730 folderview_set_folders(folderview);
732 gtk_clist_thaw(GTK_CLIST(ctree));
733 main_window_cursor_normal(mainwin);
734 STATUSBAR_POP(mainwin);
737 void folderview_set_all(void)
741 for (list = folderview_list; list != NULL; list = list->next)
742 folderview_set((FolderView *)list->data);
745 void folderview_select(FolderView *folderview, FolderItem *item)
747 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
749 GtkCTreeNode *old_selected = folderview->selected;
753 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
754 if (node) folderview_select_node(folderview, node);
756 if (old_selected != node)
757 folder_update_op_count();
760 static void mark_all_read_cb(FolderView *folderview, guint action,
766 item = folderview_get_selected_item(folderview);
770 if (folderview->summaryview->folder_item != item
771 && prefs_common.ask_mark_all_read) {
772 val = alertpanel_full(_("Mark all as read"),
773 _("Do you really want to mark all mails in this "
774 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
775 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
777 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
779 else if (val & G_ALERTDISABLE)
780 prefs_common.ask_mark_all_read = FALSE;
783 summary_lock(folderview->summaryview);
784 folder_item_update_freeze();
785 if (folderview->summaryview->folder_item == item)
786 summary_freeze(folderview->summaryview);
787 folderutils_mark_all_read(item);
788 if (folderview->summaryview->folder_item == item)
789 summary_thaw(folderview->summaryview);
790 folder_item_update_thaw();
791 summary_unlock(folderview->summaryview);
794 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
796 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
798 g_return_if_fail(node != NULL);
800 if (folderview->open_folder) {
804 folderview->open_folder = TRUE;
805 gtkut_ctree_set_focus_row(ctree, node);
806 gtk_ctree_select(ctree, node);
807 if (folderview->summaryview->folder_item &&
808 folderview->summaryview->folder_item->total_msgs > 0)
809 summary_grab_focus(folderview->summaryview);
811 gtk_widget_grab_focus(folderview->ctree);
813 gtkut_ctree_expand_parent_all(ctree, node);
816 void folderview_unselect(FolderView *folderview)
818 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
820 (GTK_CTREE(folderview->ctree), folderview->opened);
822 folderview->selected = folderview->opened = NULL;
825 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
831 node = gtkut_ctree_node_next(ctree, node);
833 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
835 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
836 item = gtk_ctree_node_get_row_data(ctree, node);
837 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
844 void folderview_select_next_marked(FolderView *folderview)
846 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
847 GtkCTreeNode *node = NULL;
848 SelectOnEntry last_sel = prefs_common.select_on_entry;
849 gboolean last_open = prefs_common.always_show_msg;
851 prefs_common.select_on_entry = SELECTONENTRY_MNU;
852 prefs_common.always_show_msg = TRUE;
854 if ((node = folderview_find_next_marked(ctree, folderview->opened))
856 folderview_select_node(folderview, node);
860 if (!folderview->opened ||
861 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
864 /* search again from the first node */
865 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
866 folderview_select_node(folderview, node);
869 prefs_common.select_on_entry = last_sel;
870 prefs_common.always_show_msg = last_open;
873 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
879 node = gtkut_ctree_node_next(ctree, node);
881 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
883 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
884 item = gtk_ctree_node_get_row_data(ctree, node);
885 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
892 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
894 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
895 GtkCTreeNode *node = NULL;
896 SelectOnEntry last_sel = prefs_common.select_on_entry;
897 gboolean last_open = prefs_common.always_show_msg;
899 prefs_common.select_on_entry = SELECTONENTRY_UNM;
900 prefs_common.always_show_msg = force_open ? TRUE : last_open;
902 if ((node = folderview_find_next_unread(ctree, folderview->opened))
904 folderview_select_node(folderview, node);
908 if (!folderview->opened ||
909 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
912 /* search again from the first node */
913 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
914 folderview_select_node(folderview, node);
917 prefs_common.select_on_entry = last_sel;
918 prefs_common.always_show_msg = last_open;
921 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
927 node = gtkut_ctree_node_next(ctree, node);
929 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
931 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
932 item = gtk_ctree_node_get_row_data(ctree, node);
933 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
940 void folderview_select_next_new(FolderView *folderview)
942 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
943 GtkCTreeNode *node = NULL;
944 SelectOnEntry last_sel = prefs_common.select_on_entry;
945 gboolean last_open = prefs_common.always_show_msg;
947 prefs_common.select_on_entry = SELECTONENTRY_NUM;
948 prefs_common.always_show_msg = TRUE;
950 if ((node = folderview_find_next_new(ctree, folderview->opened))
952 folderview_select_node(folderview, node);
956 if (!folderview->opened ||
957 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
960 /* search again from the first node */
961 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
962 folderview_select_node(folderview, node);
965 prefs_common.select_on_entry = last_sel;
966 prefs_common.always_show_msg = last_open;
969 FolderItem *folderview_get_selected_item(FolderView *folderview)
971 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
973 if (!folderview->selected) return NULL;
974 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
977 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
979 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
980 static GtkCTreeNode *prev_row = NULL;
982 gint new, unread, total;
983 gchar *new_str, *unread_str, *total_str;
984 gint *col_pos = folderview->col_pos;
988 item = gtk_ctree_node_get_row_data(ctree, row);
991 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
992 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
993 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
995 unread = atoi(unread_str);
996 total = atoi(total_str);
1000 folderview_update_node(folderview, row);
1003 void folderview_append_item(FolderItem *item)
1007 g_return_if_fail(item != NULL);
1008 g_return_if_fail(item->folder != NULL);
1009 if (folder_item_parent(item)) return;
1011 for (list = folderview_list; list != NULL; list = list->next) {
1012 FolderView *folderview = (FolderView *)list->data;
1013 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1014 GtkCTreeNode *node, *child;
1015 gint *col_pos = folderview->col_pos;
1017 node = gtk_ctree_find_by_row_data(ctree, NULL,
1018 folder_item_parent(item));
1020 child = gtk_ctree_find_by_row_data(ctree, node, item);
1022 gchar *text[N_FOLDER_COLS] =
1023 {NULL, "0", "0", "0"};
1025 gtk_clist_freeze(GTK_CLIST(ctree));
1027 text[col_pos[F_COL_FOLDER]] = item->name;
1028 child = gtk_sctree_insert_node
1029 (ctree, node, NULL, text,
1031 folderxpm, folderxpmmask,
1032 folderopenxpm, folderopenxpmmask,
1034 gtk_ctree_node_set_row_data(ctree, child, item);
1035 gtk_ctree_expand(ctree, node);
1036 folderview_update_node(folderview, child);
1037 folderview_sort_folders(folderview, node,
1040 gtk_clist_thaw(GTK_CLIST(ctree));
1046 static void folderview_set_folders(FolderView *folderview)
1049 list = folder_get_list();
1051 for (; list != NULL; list = list->next) {
1052 folderview_append_folder(folderview, FOLDER(list->data));
1056 static gchar *get_scan_str(FolderItem *item)
1059 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1060 item->folder->name, G_DIR_SEPARATOR,
1063 return g_strdup_printf(_("Scanning folder %s ..."),
1064 item->folder->name);
1066 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1070 for (list = folderview_list; list != NULL; list = list->next) {
1071 FolderView *folderview = (FolderView *)list->data;
1072 MainWindow *mainwin = folderview->mainwin;
1073 gchar *str = get_scan_str(item);
1075 STATUSBAR_PUSH(mainwin, str);
1076 STATUSBAR_POP(mainwin);
1081 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1085 g_return_if_fail(folder != NULL);
1087 if (!folder->klass->scan_tree) return;
1090 alertpanel_full(_("Rebuild folder tree"),
1091 _("Rebuilding the folder tree will remove "
1092 "local caches. Do you want to continue?"),
1093 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1094 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1095 != G_ALERTALTERNATE) {
1101 window = label_window_create(_("Rebuilding folder tree..."));
1103 window = label_window_create(_("Scanning folder tree..."));
1105 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1106 folder_scan_tree(folder, rebuild);
1107 folder_set_ui_func(folder, NULL, NULL);
1109 folderview_set_all();
1111 gtk_widget_destroy(window);
1115 /** folderview_check_new()
1116 * Scan and update the folder and return the
1117 * count the number of new messages since last check.
1118 * \param folder the folder to check for new messages
1119 * \return the number of new messages since last check
1121 gint folderview_check_new(Folder *folder)
1125 FolderView *folderview;
1129 gint former_new_msgs = 0;
1130 gint former_new = 0, former_unread = 0, former_total;
1132 for (list = folderview_list; list != NULL; list = list->next) {
1133 folderview = (FolderView *)list->data;
1134 ctree = GTK_CTREE(folderview->ctree);
1137 main_window_lock(folderview->mainwin);
1139 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1140 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1142 item = gtk_ctree_node_get_row_data(ctree, node);
1143 if (!item || !item->path || !item->folder) continue;
1144 if (item->no_select) continue;
1145 if (folder && folder != item->folder) continue;
1146 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1147 if (!item->prefs->newmailcheck) continue;
1148 if (item->processing_pending == TRUE) {
1149 debug_print("skipping %s, processing pending\n",
1150 item->path ? item->path : item->name);
1154 str = get_scan_str(item);
1156 STATUSBAR_PUSH(folderview->mainwin, str);
1160 folderview_scan_tree_func(item->folder, item, NULL);
1161 former_new = item->new_msgs;
1162 former_unread = item->unread_msgs;
1163 former_total = item->total_msgs;
1165 if (item->folder->klass->scan_required &&
1166 (item->folder->klass->scan_required(item->folder, item) ||
1167 item->folder->inbox == item ||
1168 item->opened == TRUE ||
1169 item->processing_pending == TRUE)) {
1170 if (folder_item_scan(item) < 0) {
1171 summaryview_unlock(folderview->summaryview, item);
1172 if (folder && !FOLDER_IS_LOCAL(folder)) {
1173 STATUSBAR_POP(folderview->mainwin);
1177 } else if (!item->folder->klass->scan_required) {
1178 if (folder_item_scan(item) < 0) {
1179 summaryview_unlock(folderview->summaryview, item);
1180 if (folder && !FOLDER_IS_LOCAL(folder)) {
1181 STATUSBAR_POP(folderview->mainwin);
1186 if (former_new != item->new_msgs ||
1187 former_unread != item->unread_msgs ||
1188 former_total != item->total_msgs)
1189 folderview_update_node(folderview, node);
1191 new_msgs += item->new_msgs;
1192 former_new_msgs += former_new;
1193 STATUSBAR_POP(folderview->mainwin);
1196 main_window_unlock(folderview->mainwin);
1200 folder_write_list();
1201 /* Number of new messages since last check is the just the difference
1202 * between former_new_msgs and new_msgs. If new_msgs is less than
1203 * former_new_msgs, that would mean another session accessed the folder
1204 * and the result is not well defined.
1206 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1210 void folderview_check_new_all(void)
1214 FolderView *folderview;
1216 folderview = (FolderView *)folderview_list->data;
1219 main_window_lock(folderview->mainwin);
1220 window = label_window_create
1221 (_("Checking for new messages in all folders..."));
1223 list = folder_get_list();
1224 for (; list != NULL; list = list->next) {
1225 Folder *folder = list->data;
1227 folderview_check_new(folder);
1230 folder_write_list();
1231 folderview_set_all();
1233 gtk_widget_destroy(window);
1234 main_window_unlock(folderview->mainwin);
1238 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1244 if (!item || !item->folder || !item->folder->node)
1247 node = item->folder->node;
1249 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1250 node = node->children;
1253 (item->new_msgs > 0 ||
1254 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1258 while (node != NULL) {
1259 if (node && node->data) {
1260 FolderItem *next_item = (FolderItem*) node->data;
1262 if (folderview_have_new_children_sub(folderview,
1271 static gboolean folderview_have_new_children(FolderView *folderview,
1274 return folderview_have_new_children_sub(folderview, item, FALSE);
1277 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1283 if (!item || !item->folder || !item->folder->node)
1286 node = item->folder->node;
1288 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1289 node = node->children;
1292 (item->unread_msgs > 0 ||
1293 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1297 while (node != NULL) {
1298 if (node && node->data) {
1299 FolderItem *next_item = (FolderItem*) node->data;
1301 if (folderview_have_unread_children_sub(folderview,
1311 static gboolean folderview_have_unread_children(FolderView *folderview,
1314 return folderview_have_unread_children_sub(folderview, item, FALSE);
1317 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1323 if (!item || !item->folder || !item->folder->node)
1326 node = item->folder->node;
1328 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1329 node = node->children;
1331 if (in_sub && item->search_match){
1335 while (node != NULL) {
1336 if (node && node->data) {
1337 FolderItem *next_item = (FolderItem*) node->data;
1339 if (folderview_have_matching_children_sub(folderview,
1349 static gboolean folderview_have_matching_children(FolderView *folderview,
1352 return folderview_have_matching_children_sub(folderview, item, FALSE);
1355 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1361 if (!item || !item->folder || !item->folder->node)
1364 node = item->folder->node;
1366 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1367 node = node->children;
1369 if (item->marked_msgs != 0) {
1373 while (node != NULL) {
1374 if (node && node->data) {
1375 FolderItem *next_item = (FolderItem*) node->data;
1377 if (folderview_have_marked_children_sub(folderview,
1386 static gboolean folderview_have_marked_children(FolderView *folderview,
1389 return folderview_have_marked_children_sub(folderview, item, FALSE);
1392 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1394 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1395 GtkStyle *style = NULL;
1396 GtkStyle *color_style = NULL;
1398 GdkPixmap *xpm, *openxpm;
1399 GdkBitmap *mask, *openmask;
1400 static GdkPixmap *searchicon;
1401 static GdkBitmap *searchmask;
1402 gboolean mark = FALSE;
1405 gboolean add_unread_mark;
1406 gboolean add_sub_match_mark;
1407 gboolean use_bold, use_color;
1408 gint *col_pos = folderview->col_pos;
1409 SpecialFolderItemType stype;
1411 item = gtk_ctree_node_get_row_data(ctree, node);
1412 g_return_if_fail(item != NULL);
1414 if (!GTK_CTREE_ROW(node)->expanded)
1415 mark = folderview_have_marked_children(folderview, item);
1417 mark = (item->marked_msgs != 0);
1419 stype = item->stype;
1420 if (stype == F_NORMAL) {
1421 if (folder_has_parent_of_type(item, F_TRASH))
1423 else if (folder_has_parent_of_type(item, F_DRAFT))
1425 else if (folder_has_parent_of_type(item, F_OUTBOX))
1427 else if (folder_has_parent_of_type(item, F_QUEUE))
1432 if (item->hide_read_msgs) {
1433 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1434 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1435 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1436 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1438 xpm = mark?m_inboxxpm:inboxxpm;
1439 mask = mark?m_inboxxpmmask:inboxxpmmask;
1440 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1441 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1445 if (item->hide_read_msgs) {
1446 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1447 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1448 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1449 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1451 xpm = mark?m_outboxxpm:outboxxpm;
1452 mask = mark?m_outboxxpmmask:outboxxpmmask;
1453 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1454 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1458 if (item->hide_read_msgs) {
1459 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1460 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1461 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1462 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1464 xpm = mark?m_queuexpm:queuexpm;
1465 mask = mark?m_queuexpmmask:queuexpmmask;
1466 openxpm = mark?m_queueopenxpm:queueopenxpm;
1467 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1471 if (item->hide_read_msgs) {
1472 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1473 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1474 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1475 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1477 xpm = mark?m_trashxpm:trashxpm;
1478 mask = mark?m_trashxpmmask:trashxpmmask;
1479 openxpm = mark?m_trashopenxpm:trashopenxpm;
1480 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1484 xpm = mark?m_draftsxpm:draftsxpm;
1485 mask = mark?m_draftsxpmmask:draftsxpmmask;
1486 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1487 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1490 if (item->hide_read_msgs) {
1491 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1492 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1493 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1494 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1496 xpm = mark?m_folderxpm:folderxpm;
1497 mask = mark?m_folderxpmmask:folderxpmmask;
1498 openxpm = mark?m_folderopenxpm:folderopenxpm;
1499 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1503 if (item->no_select) {
1504 xpm = openxpm = noselectxpm;
1505 mask = openmask = noselectxpmmask;
1508 name = folder_item_get_name(item);
1510 if (!GTK_CTREE_ROW(node)->expanded) {
1511 add_unread_mark = folderview_have_unread_children(
1513 add_sub_match_mark = folderview_have_matching_children(
1516 add_unread_mark = FALSE;
1517 add_sub_match_mark = FALSE;
1520 if (item->search_match) {
1522 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1523 &searchicon, &searchmask);
1525 xpm = openxpm = searchicon;
1526 mask = openmask = searchmask;
1529 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1530 prefs_common.display_folder_unread) {
1531 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1532 add_unread_mark ? "+" : "");
1533 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1534 xpm, mask, openxpm, openmask,
1535 FALSE, GTK_CTREE_ROW(node)->expanded);
1537 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1538 prefs_common.display_folder_unread)
1539 || add_sub_match_mark) {
1541 if (item->unread_msgs > 0)
1542 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1543 add_unread_mark || add_sub_match_mark ? "+" : "",
1544 item->unreadmarked_msgs > 0 ? "!":"");
1546 str = g_strdup_printf("%s (+)", name);
1547 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1548 xpm, mask, openxpm, openmask,
1549 FALSE, GTK_CTREE_ROW(node)->expanded);
1552 str = g_strdup_printf("%s%s", name,
1553 item->unreadmarked_msgs > 0 ? " (!)":"");
1555 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1556 xpm, mask, openxpm, openmask,
1557 FALSE, GTK_CTREE_ROW(node)->expanded);
1562 if (!folder_item_parent(item)) {
1563 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1564 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1565 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1567 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1568 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1569 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1572 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1573 folder_has_parent_of_type(item, F_DRAFT) ||
1574 folder_has_parent_of_type(item, F_TRASH)) {
1575 use_bold = use_color = FALSE;
1576 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1577 /* highlight queue folder if there are any messages */
1578 use_bold = use_color = (item->total_msgs > 0);
1580 /* if unread messages exist, print with bold font */
1581 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1583 /* if new messages exist, print with colored letter */
1585 (item->new_msgs > 0) ||
1587 folderview_have_new_children(folderview, item));
1590 gtk_ctree_node_set_foreground(ctree, node, NULL);
1595 if (item->prefs->color > 0 && !use_color) {
1596 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1597 color_style = gtk_style_copy(bold_style);
1598 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1599 style = color_style;
1600 } else if (use_color) {
1601 style = bold_color_style;
1604 if (item->op_count > 0) {
1605 style = bold_tgtfold_style;
1607 } else if (use_color) {
1608 style = normal_color_style;
1609 gtk_ctree_node_set_foreground(ctree, node,
1610 &folderview->color_new);
1611 } else if (item->op_count > 0) {
1612 style = bold_tgtfold_style;
1613 } else if (item->prefs->color > 0) {
1615 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1616 color_style = gtk_style_copy(normal_style);
1617 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1618 style = color_style;
1620 style = normal_style;
1623 gtk_ctree_node_set_row_style(ctree, node, style);
1625 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1626 folderview_update_node(folderview, node);
1629 #if !CLAWS /* keep it here for syncs */
1630 void folderview_update_item(FolderItem *item, gboolean update_summary)
1633 FolderView *folderview;
1637 g_return_if_fail(item != NULL);
1639 for (list = folderview_list; list != NULL; list = list->next) {
1640 folderview = (FolderView *)list->data;
1641 ctree = GTK_CTREE(folderview->ctree);
1643 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1645 folderview_update_node(folderview, node);
1646 if (update_summary && folderview->opened == node)
1647 summary_show(folderview->summaryview,
1654 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1657 FolderView *folderview;
1661 g_return_if_fail(item != NULL);
1663 for (list = folderview_list; list != NULL; list = list->next) {
1664 folderview = (FolderView *)list->data;
1665 ctree = GTK_CTREE(folderview->ctree);
1667 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1669 item->search_match = matches;
1670 folderview_update_node(folderview, node);
1675 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1677 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1678 FolderView *folderview = (FolderView *)data;
1681 g_return_val_if_fail(update_info != NULL, TRUE);
1682 g_return_val_if_fail(update_info->item != NULL, TRUE);
1683 g_return_val_if_fail(folderview != NULL, FALSE);
1685 ctree = GTK_CTREE(folderview->ctree);
1687 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1690 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1691 folderview_update_node(folderview, node);
1692 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1693 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1694 summary_show(folderview->summaryview, update_info->item);
1700 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1703 /* CLAWS: share this joy with other hook functions ... */
1704 folder_item_update((FolderItem *)key,
1705 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1708 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1711 FolderItemUpdateFlags flags;
1713 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1715 for (list = folderview_list; list != NULL; list = list->next)
1716 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1717 GINT_TO_POINTER(flags));
1720 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1721 GNode *gnode, GtkCTreeNode *cnode,
1724 FolderView *folderview = (FolderView *)data;
1725 FolderItem *item = FOLDER_ITEM(gnode->data);
1727 g_return_val_if_fail(item != NULL, FALSE);
1729 gtk_ctree_node_set_row_data(ctree, cnode, item);
1730 folderview_update_node(folderview, cnode);
1735 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1738 FolderView *folderview = (FolderView *)data;
1741 if (GTK_CTREE_ROW(node)->children) {
1742 item = gtk_ctree_node_get_row_data(ctree, node);
1743 g_return_if_fail(item != NULL);
1745 if (!item->collapsed)
1746 gtk_ctree_expand(ctree, node);
1748 folderview_update_node(folderview, node);
1752 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1753 GtkCTreeNode *root, GtkCTreeNode **prev)
1756 GtkCTreeNode *node, *parent, *sibling;
1758 node = gtk_ctree_find_by_row_data(ctree, root, item);
1760 g_warning("%s not found.\n", item->path);
1762 parent = GTK_CTREE_ROW(node)->parent;
1763 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1764 sibling = GTK_CTREE_ROW(*prev)->sibling;
1766 sibling = GTK_CTREE_ROW(parent)->children;
1770 tmp = gtk_ctree_node_get_row_data
1772 if (tmp->stype != F_NORMAL)
1773 sibling = GTK_CTREE_ROW(sibling)->sibling;
1777 if (node != sibling)
1778 gtk_ctree_move(ctree, node, parent, sibling);
1785 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1788 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1789 GtkCTreeNode *prev = NULL;
1791 gtk_clist_freeze(GTK_CLIST(ctree));
1792 gtk_sctree_sort_recursive(ctree, root);
1793 if (root && GTK_CTREE_ROW(root)->parent) {
1794 gtk_clist_thaw(GTK_CLIST(ctree));
1797 set_special_folder(ctree, folder->inbox, root, &prev);
1798 set_special_folder(ctree, folder->outbox, root, &prev);
1799 set_special_folder(ctree, folder->draft, root, &prev);
1800 set_special_folder(ctree, folder->queue, root, &prev);
1801 set_special_folder(ctree, folder->trash, root, &prev);
1802 gtk_clist_thaw(GTK_CLIST(ctree));
1805 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1807 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1810 g_return_if_fail(folder != NULL);
1812 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1813 folderview_gnode_func, folderview);
1814 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1816 folderview_sort_folders(folderview, root, folder);
1819 /* callback functions */
1820 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1821 GdkEventButton *event)
1823 GtkCList *clist = GTK_CLIST(folderview->ctree);
1826 FolderViewPopup *fpopup;
1827 GtkItemFactory *fpopup_factory;
1829 FolderItem *special_trash = NULL, *special_queue = NULL;
1833 item = gtk_clist_get_row_data(clist, row);
1835 item = folderview_get_selected_item(folderview);
1837 g_return_if_fail(item != NULL);
1838 g_return_if_fail(item->folder != NULL);
1839 folder = item->folder;
1841 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1843 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1845 fpopup = g_hash_table_lookup(folderview_popups, "common");
1846 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1849 if (fpopup->set_sensitivity != NULL)
1850 fpopup->set_sensitivity(fpopup_factory, item);
1852 if (NULL != (ac = account_find_from_item(item))) {
1853 special_trash = account_get_special_folder(ac, F_TRASH);
1854 special_queue = account_get_special_folder(ac, F_QUEUE);
1857 if ((item == folder->trash || item == special_trash
1858 || folder_has_parent_of_type(item, F_TRASH)) &&
1859 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1860 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1861 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1862 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1863 && !folder_has_parent_of_type(item, F_TRASH)) {
1864 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1865 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1868 if ((item == folder->queue || item == special_queue
1869 || folder_has_parent_of_type(item, F_QUEUE)) &&
1870 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1871 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1872 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1873 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1874 && !folder_has_parent_of_type(item, F_QUEUE)) {
1875 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1876 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1879 #define SET_SENS(name, sens) \
1880 menu_set_sensitive(fpopup_factory, name, sens)
1882 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1883 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1884 folderview->selected == folderview->opened);
1885 SET_SENS("/Properties...", TRUE);
1886 SET_SENS("/Processing...", item->node->parent != NULL);
1887 if (item == folder->trash || item == special_trash
1888 || folder_has_parent_of_type(item, F_TRASH)) {
1889 GSList *msglist = folder_item_get_msg_list(item);
1890 SET_SENS("/Empty trash...", msglist != NULL);
1891 procmsg_msg_list_free(msglist);
1893 if (item == folder->queue || item == special_queue
1894 || folder_has_parent_of_type(item, F_QUEUE)) {
1895 GSList *msglist = folder_item_get_msg_list(item);
1896 SET_SENS("/Send queue...", msglist != NULL);
1897 procmsg_msg_list_free(msglist);
1901 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1902 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1903 event->button, event->time);
1908 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1909 FolderView *folderview)
1911 GtkCList *clist = GTK_CLIST(ctree);
1912 gint prev_row = -1, row = -1, column = -1;
1914 if (!event) return FALSE;
1916 if (event->button == 1 || event->button == 2) {
1917 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1918 folderview->open_folder = TRUE;
1920 if (event->type == GDK_2BUTTON_PRESS) {
1921 if (clist->selection) {
1924 node = GTK_CTREE_NODE(clist->selection->data);
1926 gtk_ctree_toggle_expansion(
1929 folderview->open_folder = FALSE;
1936 if (event->button == 2 || event->button == 3) {
1938 if (clist->selection) {
1941 node = GTK_CTREE_NODE(clist->selection->data);
1943 prev_row = gtkut_ctree_get_nth_from_node
1944 (GTK_CTREE(ctree), node);
1947 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1950 if (prev_row != row) {
1951 gtk_clist_unselect_all(clist);
1952 if (event->button == 2)
1953 folderview_select_node
1955 gtk_ctree_node_nth(GTK_CTREE(ctree),
1958 gtk_clist_select_row(clist, row, column);
1962 if (event->button != 3) return FALSE;
1964 folderview_set_sens_and_popup_menu(folderview, row, event);
1968 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1969 FolderView *folderview)
1971 if (!event) return FALSE;
1973 if (event->button == 1 && folderview->open_folder == FALSE &&
1974 folderview->opened != NULL) {
1975 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1976 folderview->opened);
1977 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1983 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1984 FolderView *folderview)
1986 if (!event) return FALSE;
1988 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1991 switch (event->keyval) {
1993 if (folderview->selected) {
1994 folderview_select_node(folderview,
1995 folderview->selected);
1999 if (folderview->selected) {
2000 if (folderview->opened == folderview->selected &&
2001 (!folderview->summaryview->folder_item ||
2002 folderview->summaryview->folder_item->total_msgs == 0))
2003 folderview_select_next_unread(folderview, TRUE);
2005 folderview_select_node(folderview,
2006 folderview->selected);
2016 typedef struct _PostponedSelectData
2021 FolderView *folderview;
2022 } PostponedSelectData;
2024 static gboolean postpone_select(void *data)
2026 PostponedSelectData *psdata = (PostponedSelectData *)data;
2027 debug_print("trying again\n");
2028 psdata->folderview->open_folder = TRUE;
2029 main_window_cursor_normal(psdata->folderview->mainwin);
2030 STATUSBAR_POP(psdata->folderview->mainwin);
2031 folderview_selected(psdata->ctree, psdata->row,
2032 psdata->column, psdata->folderview);
2037 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2038 gint column, FolderView *folderview)
2040 static gboolean can_select = TRUE; /* exclusive lock */
2046 folderview->selected = row;
2048 if (folderview->opened == row) {
2049 folderview->open_folder = FALSE;
2054 if (!can_select || summary_is_locked(folderview->summaryview)) {
2055 if (folderview->opened) {
2056 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2057 gtk_ctree_select(ctree, folderview->opened);
2063 if (!folderview->open_folder) {
2067 item = gtk_ctree_node_get_row_data(ctree, row);
2068 if (!item || item->no_select) {
2070 folderview->open_folder = FALSE;
2076 /* Save cache for old folder */
2077 /* We don't want to lose all caches if sylpheed crashed */
2078 if (folderview->opened) {
2079 FolderItem *olditem;
2081 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2083 buf = g_strdup_printf(_("Closing Folder %s..."),
2084 olditem->path ? olditem->path:olditem->name);
2085 /* will be null if we just moved the previously opened folder */
2086 STATUSBAR_PUSH(folderview->mainwin, buf);
2087 main_window_cursor_wait(folderview->mainwin);
2089 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2090 summary_show(folderview->summaryview, NULL);
2091 folder_item_close(olditem);
2092 main_window_cursor_normal(folderview->mainwin);
2093 STATUSBAR_POP(folderview->mainwin);
2097 /* CLAWS: set compose button type: news folder items
2098 * always have a news folder as parent */
2100 toolbar_set_compose_button
2101 (folderview->mainwin->toolbar,
2102 FOLDER_TYPE(item->folder) == F_NEWS ?
2103 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2106 debug_print("Folder %s is selected\n", item->path);
2108 if (!GTK_CTREE_ROW(row)->children)
2109 gtk_ctree_expand(ctree, row);
2110 if (folderview->opened &&
2111 !GTK_CTREE_ROW(folderview->opened)->children)
2112 gtk_ctree_collapse(ctree, folderview->opened);
2114 /* ungrab the mouse event */
2115 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2116 gtk_grab_remove(GTK_WIDGET(ctree));
2117 if (gdk_pointer_is_grabbed())
2118 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2122 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2123 item->path : "(null)");
2124 debug_print("%s\n", buf);
2125 STATUSBAR_PUSH(folderview->mainwin, buf);
2128 main_window_cursor_wait(folderview->mainwin);
2130 res = folder_item_open(item);
2132 main_window_cursor_normal(folderview->mainwin);
2133 STATUSBAR_POP(folderview->mainwin);
2135 alertpanel_error(_("Folder could not be opened."));
2137 folderview->open_folder = FALSE;
2141 } else if (res == -2) {
2142 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2143 data->ctree = ctree;
2145 data->column = column;
2146 data->folderview = folderview;
2147 debug_print("postponing open of %s till end of scan\n",
2148 item->path ? item->path:item->name);
2149 folderview->open_folder = FALSE;
2151 g_timeout_add(500, postpone_select, data);
2156 main_window_cursor_normal(folderview->mainwin);
2159 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2160 opened = summary_show(folderview->summaryview, item);
2162 folder_clean_cache_memory(item);
2165 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2166 gtk_ctree_select(ctree, folderview->opened);
2168 folderview->opened = row;
2169 if (gtk_ctree_node_is_visible(ctree, row)
2170 != GTK_VISIBILITY_FULL)
2171 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2174 STATUSBAR_POP(folderview->mainwin);
2176 folderview->open_folder = FALSE;
2181 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2182 FolderView *folderview)
2186 item = gtk_ctree_node_get_row_data(ctree, node);
2187 g_return_if_fail(item != NULL);
2188 item->collapsed = FALSE;
2189 folderview_update_node(folderview, node);
2192 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2193 FolderView *folderview)
2197 item = gtk_ctree_node_get_row_data(ctree, node);
2198 g_return_if_fail(item != NULL);
2199 item->collapsed = TRUE;
2200 folderview_update_node(folderview, node);
2203 static void folderview_popup_close(GtkMenuShell *menu_shell,
2204 FolderView *folderview)
2206 if (!folderview->opened) return;
2208 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2211 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2212 FolderView *folderview)
2214 FolderColumnType type = folderview->col_state[column].type;
2216 prefs_common.folder_col_size[type] = width;
2219 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2223 folderview_create_folder_node(folderview, item);
2225 if (!item || !item->folder || !item->folder->node)
2228 srcnode = item->folder->node;
2229 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2230 srcnode = srcnode->children;
2231 while (srcnode != NULL) {
2232 if (srcnode && srcnode->data) {
2233 FolderItem *next_item = (FolderItem*) srcnode->data;
2234 folderview_create_folder_node_recursive(folderview, next_item);
2236 srcnode = srcnode->next;
2240 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2242 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2243 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2244 GtkCTreeNode *node, *parent_node;
2245 gint *col_pos = folderview->col_pos;
2246 FolderItemUpdateData hookdata;
2248 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2249 if (parent_node == NULL)
2252 gtk_clist_freeze(GTK_CLIST(ctree));
2254 text[col_pos[F_COL_FOLDER]] = item->name;
2255 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2257 folderxpm, folderxpmmask,
2258 folderopenxpm, folderopenxpmmask,
2260 gtk_ctree_expand(ctree, parent_node);
2261 gtk_ctree_node_set_row_data(ctree, node, item);
2263 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2264 folderview_sort_folders(folderview, parent_node, item->folder);
2266 hookdata.item = item;
2267 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2268 hookdata.msg = NULL;
2269 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2271 gtk_clist_thaw(GTK_CLIST(ctree));
2274 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2277 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2279 GSList *mlist = NULL;
2281 FolderItem *special_trash = NULL;
2284 if (!folderview->selected) return;
2285 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2286 g_return_if_fail(item != NULL);
2287 g_return_if_fail(item->folder != NULL);
2289 if (NULL != (ac = account_find_from_item(item)))
2290 special_trash = account_get_special_folder(ac, F_TRASH);
2292 if (item != item->folder->trash && item != special_trash
2293 && !folder_has_parent_of_type(item, F_TRASH)) return;
2295 if (prefs_common.ask_on_clean) {
2296 if (alertpanel(_("Empty trash"),
2297 _("Delete all messages in trash?"),
2298 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2302 mlist = folder_item_get_msg_list(item);
2304 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2305 MsgInfo * msginfo = (MsgInfo *) cur->data;
2306 if (MSG_IS_LOCKED(msginfo->flags))
2308 /* is it partially received? (partial_recv isn't cached) */
2309 if (msginfo->total_size != 0 &&
2310 msginfo->size != (off_t)msginfo->total_size)
2311 partial_mark_for_delete(msginfo);
2313 procmsg_msg_list_free(mlist);
2315 folder_item_remove_all_msg(item);
2318 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2321 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2323 FolderItem *special_queue = NULL;
2325 gchar *errstr = NULL;
2327 if (!folderview->selected) return;
2328 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2329 g_return_if_fail(item != NULL);
2330 g_return_if_fail(item->folder != NULL);
2332 if (NULL != (ac = account_find_from_item(item)))
2333 special_queue = account_get_special_folder(ac, F_QUEUE);
2335 if (item != item->folder->queue && item != special_queue
2336 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2338 if (procmsg_queue_is_empty(item))
2341 if (prefs_common.work_offline)
2342 if (alertpanel(_("Offline warning"),
2343 _("You're working offline. Override?"),
2344 GTK_STOCK_NO, GTK_STOCK_YES,
2345 NULL) != G_ALERTALTERNATE)
2348 /* ask for confirmation before sending queued messages only
2349 in online mode and if there is at least one message queued
2350 in any of the folder queue
2352 if (prefs_common.confirm_send_queued_messages) {
2353 if (!prefs_common.work_offline) {
2354 if (alertpanel(_("Send queued messages"),
2355 _("Send all queued messages?"),
2356 GTK_STOCK_CANCEL, _("_Send"),
2357 NULL) != G_ALERTALTERNATE)
2362 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2364 alertpanel_error_log(_("Some errors occurred while "
2365 "sending queued messages."));
2367 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2368 "while sending queued messages:\n%s"), errstr);
2370 alertpanel_error_log(tmp);
2376 static void folderview_search_cb(FolderView *folderview, guint action,
2379 summary_search(folderview->summaryview);
2382 static void folderview_property_cb(FolderView *folderview, guint action,
2385 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2388 if (!folderview->selected) return;
2390 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2391 g_return_if_fail(item != NULL);
2392 g_return_if_fail(item->folder != NULL);
2394 prefs_folder_item_open(item);
2397 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2399 GSList *list = NULL;
2400 GSList *done = NULL;
2401 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2403 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2404 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2405 && list->data != node) {
2406 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2407 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2410 for (list = done; list != NULL; list = g_slist_next(list)) {
2411 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2417 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2418 FolderItem *to_folder)
2420 FolderItem *from_parent = NULL;
2421 FolderItem *new_folder = NULL;
2422 GtkCTreeNode *src_node = NULL;
2426 g_return_if_fail(folderview != NULL);
2427 g_return_if_fail(from_folder != NULL);
2428 g_return_if_fail(to_folder != NULL);
2430 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2431 from_parent = folder_item_parent(from_folder);
2433 if (prefs_common.warn_dnd) {
2434 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2435 "sub-folder of '%s' ?"), from_folder->name,
2437 status = alertpanel_full(_("Move folder"), buf,
2438 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2439 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2442 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2444 else if (status & G_ALERTDISABLE)
2445 prefs_common.warn_dnd = FALSE;
2448 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2449 STATUSBAR_PUSH(folderview->mainwin, buf);
2451 summary_clear_all(folderview->summaryview);
2452 folderview->opened = NULL;
2453 folderview->selected = NULL;
2454 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2456 main_window_cursor_wait(folderview->mainwin);
2457 statusbar_verbosity_set(TRUE);
2458 folder_item_update_freeze();
2459 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2460 statusbar_verbosity_set(FALSE);
2461 main_window_cursor_normal(folderview->mainwin);
2462 STATUSBAR_POP(folderview->mainwin);
2463 folder_item_update_thaw();
2464 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2466 folderview_sort_folders(folderview,
2467 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2468 NULL, to_folder), new_folder->folder);
2469 folderview_select(folderview, new_folder);
2471 statusbar_verbosity_set(FALSE);
2472 main_window_cursor_normal(folderview->mainwin);
2473 STATUSBAR_POP(folderview->mainwin);
2474 folder_item_update_thaw();
2476 case F_MOVE_FAILED_DEST_IS_PARENT:
2477 alertpanel_error(_("Source and destination are the same."));
2479 case F_MOVE_FAILED_DEST_IS_CHILD:
2480 alertpanel_error(_("Can't move a folder to one of its children."));
2482 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2483 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2486 alertpanel_error(_("Move failed!"));
2491 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2494 static gint folderview_clist_compare(GtkCList *clist,
2495 gconstpointer ptr1, gconstpointer ptr2)
2497 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2498 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2501 return (item2->name != NULL);
2505 return g_utf8_collate(item1->name, item2->name);
2508 static void folderview_processing_cb(FolderView *folderview, guint action,
2511 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2515 if (!folderview->selected) return;
2517 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2518 g_return_if_fail(item != NULL);
2519 g_return_if_fail(item->folder != NULL);
2521 id = folder_item_get_identifier(item);
2522 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2525 prefs_filtering_open(&item->prefs->processing, title,
2526 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2530 void folderview_set_target_folder_color(gint color_op)
2534 FolderView *folderview;
2536 for (list = folderview_list; list != NULL; list = list->next) {
2537 folderview = (FolderView *)list->data;
2538 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2540 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2541 folderview->color_op;
2547 static gchar *last_font = NULL;
2548 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2556 void folderview_reflect_prefs(void)
2558 gboolean update_font = TRUE;
2559 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2560 FolderItem *item = folderview_get_selected_item(folderview);
2561 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2562 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2563 gint height = pos->value;
2565 if (last_font && !strcmp(last_font, NORMAL_FONT))
2566 update_font = FALSE;
2569 last_font = g_strdup(NORMAL_FONT);
2572 normal_style = normal_color_style = bold_style =
2573 bold_color_style = bold_tgtfold_style = NULL;
2575 folderview_init(folderview);
2577 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2578 folderview_column_set_titles(folderview);
2579 folderview_set_all();
2581 g_signal_handlers_block_by_func
2582 (G_OBJECT(folderview->ctree),
2583 G_CALLBACK(folderview_selected), folderview);
2586 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2587 GTK_CTREE(folderview->ctree), NULL, item);
2589 folderview_select(folderview, item);
2590 folderview->open_folder = FALSE;
2591 folderview->selected = node;
2594 g_signal_handlers_unblock_by_func
2595 (G_OBJECT(folderview->ctree),
2596 G_CALLBACK(folderview_selected), folderview);
2598 pos = gtk_scrolled_window_get_vadjustment(
2599 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2600 gtk_adjustment_set_value(pos, height);
2601 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2604 static void drag_state_stop(FolderView *folderview)
2606 if (folderview->drag_timer)
2607 gtk_timeout_remove(folderview->drag_timer);
2608 folderview->drag_timer = 0;
2609 folderview->drag_node = NULL;
2612 static gint folderview_defer_expand(FolderView *folderview)
2614 if (folderview->drag_node) {
2615 folderview_recollapse_nodes(folderview, folderview->drag_node);
2616 if (folderview->drag_item->collapsed) {
2617 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2618 folderview->nodes_to_recollapse = g_slist_append
2619 (folderview->nodes_to_recollapse, folderview->drag_node);
2622 folderview->drag_item = NULL;
2623 folderview->drag_timer = 0;
2627 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2629 /* the idea is that we call drag_state_start() whenever we want expansion to
2630 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2631 * we need to call drag_state_stop() */
2632 drag_state_stop(folderview);
2633 /* request expansion */
2634 if (0 != (folderview->drag_timer = gtk_timeout_add
2635 (prefs_common.hover_timeout,
2636 (GtkFunction)folderview_defer_expand,
2638 folderview->drag_node = node;
2639 folderview->drag_item = item;
2643 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2644 FolderView *folderview)
2646 GdkDragContext *context;
2648 g_return_if_fail(folderview != NULL);
2649 if (folderview->selected == NULL) return;
2650 if (folderview->nodes_to_recollapse)
2651 g_slist_free(folderview->nodes_to_recollapse);
2652 folderview->nodes_to_recollapse = NULL;
2653 context = gtk_drag_begin(widget, folderview->target_list,
2654 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2655 gtk_drag_set_icon_default(context);
2658 static void folderview_drag_data_get(GtkWidget *widget,
2659 GdkDragContext *drag_context,
2660 GtkSelectionData *selection_data,
2663 FolderView *folderview)
2667 gchar *source = NULL;
2668 if (info == TARGET_DUMMY) {
2669 for (cur = GTK_CLIST(folderview->ctree)->selection;
2670 cur != NULL; cur = cur->next) {
2671 item = gtk_ctree_node_get_row_data
2672 (GTK_CTREE(folderview->ctree),
2673 GTK_CTREE_NODE(cur->data));
2675 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2676 gtk_selection_data_set(selection_data,
2677 selection_data->target, 8,
2678 source, strlen(source));
2684 g_warning("unknown info %d\n", info);
2688 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2690 FolderUpdateData *hookdata;
2691 FolderView *folderview;
2695 folderview = (FolderView *) userdata;
2696 g_return_val_if_fail(hookdata != NULL, FALSE);
2697 g_return_val_if_fail(folderview != NULL, FALSE);
2699 ctree = folderview->ctree;
2700 g_return_val_if_fail(ctree != NULL, FALSE);
2702 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2703 folderview_create_folder_node(folderview, hookdata->item);
2704 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2705 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2706 NULL, folder_item_parent(hookdata->item));
2707 folderview_sort_folders(folderview, node, hookdata->folder);
2708 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2711 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2713 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2714 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2715 folderview_set(folderview);
2720 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2721 GdkDragContext *context,
2725 FolderView *folderview)
2728 FolderItem *item = NULL, *src_item = NULL;
2729 GtkCTreeNode *node = NULL;
2730 gboolean acceptable = FALSE;
2731 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2732 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2733 int height = (int)pos->page_size;
2734 int total_height = (int)pos->upper;
2735 int vpos = (int) pos->value;
2737 if (gtk_clist_get_selection_info
2738 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2739 GtkWidget *srcwidget;
2741 if (y > height - 24 && height + vpos < total_height)
2742 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2744 if (y < 48 && y > 0)
2745 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2747 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2748 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2749 src_item = folderview->summaryview->folder_item;
2751 srcwidget = gtk_drag_get_source_widget(context);
2752 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2753 /* comes from summaryview */
2754 /* we are copying messages, so only accept folder items that are not
2755 the source item, are no root items and can copy messages */
2756 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2757 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2758 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2760 } else if (srcwidget == folderview->ctree) {
2761 /* comes from folderview */
2762 /* we are moving folder items, only accept folders that are not
2763 the source items and can copy messages and create folder items */
2764 if (item && item->folder && src_item && src_item != item &&
2765 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2766 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2767 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2768 || item->folder == src_item->folder))
2771 /* comes from another app */
2772 /* we are adding messages, so only accept folder items that are
2773 no root items and can copy messages */
2774 if (item && item->folder && folder_item_parent(item) != NULL
2775 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2776 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2781 if (acceptable || (src_item && src_item == item))
2782 drag_state_start(folderview, node, item);
2785 g_signal_handlers_block_by_func
2787 G_CALLBACK(folderview_selected), folderview);
2788 gtk_ctree_select(GTK_CTREE(widget), node);
2789 g_signal_handlers_unblock_by_func
2791 G_CALLBACK(folderview_selected), folderview);
2792 gdk_drag_status(context,
2793 (context->actions == GDK_ACTION_COPY ?
2794 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2796 if (folderview->opened)
2797 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2798 gdk_drag_status(context, 0, time);
2804 static void folderview_drag_leave_cb(GtkWidget *widget,
2805 GdkDragContext *context,
2807 FolderView *folderview)
2809 drag_state_stop(folderview);
2810 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2813 static void free_info (gpointer stuff, gpointer data)
2818 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2819 guint time, FolderItem *item)
2822 GSList *msglist = NULL;
2823 list = uri_list_extract_filenames(data);
2824 if (!(item && item->folder && folder_item_parent(item) != NULL
2825 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2827 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2831 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2834 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2835 MsgFileInfo *info = NULL;
2837 if (file_is_email((gchar *)tmp->data)) {
2838 info = g_new0(MsgFileInfo, 1);
2839 info->msginfo = NULL;
2840 info->file = (gchar *)tmp->data;
2841 msglist = g_slist_prepend(msglist, info);
2845 msglist = g_slist_reverse(msglist);
2846 folder_item_add_msgs(item, msglist, FALSE);
2847 g_slist_foreach(msglist, free_info, NULL);
2848 g_slist_free(msglist);
2849 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2851 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2853 list_free_strings(list);
2857 static void folderview_drag_received_cb(GtkWidget *widget,
2858 GdkDragContext *drag_context,
2861 GtkSelectionData *data,
2864 FolderView *folderview)
2867 FolderItem *item = NULL, *src_item;
2870 if (info == TARGET_DUMMY) {
2871 drag_state_stop(folderview);
2872 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2873 /* comes from summaryview */
2874 if (gtk_clist_get_selection_info
2875 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2878 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2879 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2880 src_item = folderview->summaryview->folder_item;
2882 /* re-check (due to acceptable possibly set for folder moves */
2883 if (!(item && item->folder && item->path && !item->no_select &&
2884 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2887 if (item && src_item) {
2888 switch (drag_context->action) {
2889 case GDK_ACTION_COPY:
2890 summary_copy_selected_to(folderview->summaryview, item);
2891 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2893 case GDK_ACTION_MOVE:
2894 case GDK_ACTION_DEFAULT:
2896 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2897 summary_copy_selected_to(folderview->summaryview, item);
2899 summary_move_selected_to(folderview->summaryview, item);
2900 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2903 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2905 /* comes from folderview */
2907 gboolean folder_is_normal = TRUE;
2909 source = data->data + 17;
2910 if (gtk_clist_get_selection_info
2911 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2913 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2916 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2917 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2918 src_item = folder_find_item_from_identifier(source);
2922 src_item->stype == F_NORMAL &&
2923 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2924 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2925 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2926 !folder_has_parent_of_type(src_item, F_TRASH);
2927 if (!item || item->no_select || !src_item
2928 || !folder_is_normal) {
2929 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2933 folderview_move_folder(folderview, src_item, item);
2934 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2936 folderview->nodes_to_recollapse = NULL;
2937 } else if (info == TARGET_MAIL_URI_LIST) {
2938 if (gtk_clist_get_selection_info
2939 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2942 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2944 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2947 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2949 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2952 folderview_finish_dnd(data->data, drag_context, time, item);
2956 static void folderview_drag_end_cb(GtkWidget *widget,
2957 GdkDragContext *drag_context,
2958 FolderView *folderview)
2960 drag_state_stop(folderview);
2961 g_slist_free(folderview->nodes_to_recollapse);
2962 folderview->nodes_to_recollapse = NULL;
2965 void folderview_register_popup(FolderViewPopup *fpopup)
2969 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2970 FolderView *folderview = folderviews->data;
2971 GtkItemFactory *factory;
2973 factory = create_ifactory(folderview, fpopup);
2974 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2976 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2979 void folderview_unregister_popup(FolderViewPopup *fpopup)
2983 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2984 FolderView *folderview = folderviews->data;
2986 g_hash_table_remove(folderview->popups, fpopup->klass);
2988 g_hash_table_remove(folderview_popups, fpopup->klass);